Merge "Disable UpdateService temporarily."
diff --git a/Android.bp b/Android.bp
index b9a8dec..2685ac3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -471,8 +471,6 @@
         "telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl",
         "telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl",
         "telephony/java/android/telephony/ims/internal/aidl/IImsRcsFeature.aidl",
-        "telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl",
-        "telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl",
         "telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl",
         "telephony/java/android/telephony/ims/internal/aidl/IImsServiceControllerListener.aidl",
 	"telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl",
@@ -492,6 +490,8 @@
         "telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl",
         "telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl",
         "telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl",
+        "telephony/java/com/android/ims/internal/IImsRegistration.aidl",
+        "telephony/java/com/android/ims/internal/IImsRegistrationCallback.aidl",
         "telephony/java/com/android/ims/internal/IImsRcsFeature.aidl",
         "telephony/java/com/android/ims/internal/IImsService.aidl",
         "telephony/java/com/android/ims/internal/IImsServiceController.aidl",
@@ -519,7 +519,9 @@
         "telephony/java/com/android/internal/telephony/ITelephony.aidl",
         "telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl",
         "telephony/java/com/android/internal/telephony/IWapPushManager.aidl",
+        "telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl",
         "telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl",
+        "telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl",
         "wifi/java/android/net/wifi/IWifiManager.aidl",
         "wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl",
         "wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl",
@@ -618,6 +620,7 @@
         "android.hardware.vibrator-V1.0-java-constants",
         "android.hardware.vibrator-V1.1-java-constants",
         "android.hardware.wifi-V1.0-java-constants",
+        "android.hardware.radio-V1.0-java",
     ],
 
     // Loaded with System.loadLibrary by android.view.textclassifier
diff --git a/Android.mk b/Android.mk
index 8199c57..3c6dd37 100644
--- a/Android.mk
+++ b/Android.mk
@@ -829,4 +829,4 @@
 include $(call first-makefiles-under,$(LOCAL_PATH))
 endif
 
-endif # ANDROID_BUILD_EMBEDDED
+endif # ANDROID_BUILD_EMBEDDED
\ No newline at end of file
diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml
index 4889941..bd0b944 100644
--- a/apct-tests/perftests/core/AndroidManifest.xml
+++ b/apct-tests/perftests/core/AndroidManifest.xml
@@ -2,6 +2,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.perftests.core">
 
+    <permission android:name="com.android.perftests.core.TestPermission" />
+    <uses-permission android:name="com.android.perftests.core.TestPermission" />
+
     <uses-permission
         android:name="android.permission.GET_ACCOUNTS" />
 
diff --git a/apct-tests/perftests/core/src/android/os/PermissionTest.java b/apct-tests/perftests/core/src/android/os/PermissionTest.java
new file mode 100644
index 0000000..d292e7d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/PermissionTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.os;
+
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.content.Context;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class PermissionTest {
+    private static final String PERMISSION_HAS_NAME = "com.android.perftests.core.TestPermission";
+    private static final String PERMISSION_DOESNT_HAVE_NAME =
+            "com.android.perftests.core.TestBadPermission";
+    private static final String THIS_PACKAGE_NAME = "com.android.perftests.core";
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testHasPermission() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Context context = InstrumentationRegistry.getTargetContext();
+        while (state.keepRunning()) {
+            int ret = context.getPackageManager().checkPermission(PERMISSION_HAS_NAME,
+                    THIS_PACKAGE_NAME);
+        }
+    }
+
+    @Test
+    public void testDoesntHavePermission() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Context context = InstrumentationRegistry.getTargetContext();
+
+        while (state.keepRunning()) {
+            int ret = context.getPackageManager().checkPermission(PERMISSION_DOESNT_HAVE_NAME,
+                    THIS_PACKAGE_NAME);
+        }
+    }
+
+}
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 5653a03..93a0fc3 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -190,7 +190,7 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final PremeasuredText text = PremeasuredText.build(
+            final MeasuredText text = MeasuredText.build(
                     generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
             state.resumeTiming();
 
@@ -206,7 +206,7 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final PremeasuredText text = PremeasuredText.build(
+            final MeasuredText text = MeasuredText.build(
                     generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
             state.resumeTiming();
 
@@ -222,7 +222,7 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final PremeasuredText text = PremeasuredText.build(
+            final MeasuredText text = MeasuredText.build(
                     generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
             state.resumeTiming();
 
@@ -238,7 +238,7 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final PremeasuredText text = PremeasuredText.build(
+            final MeasuredText text = MeasuredText.build(
                     generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
             state.resumeTiming();
 
@@ -254,7 +254,7 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final PremeasuredText text = PremeasuredText.build(
+            final MeasuredText text = MeasuredText.build(
                     generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT, LTR);
             state.resumeTiming();
 
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index bb9dc4a..da17818 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -25,7 +25,6 @@
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -78,10 +77,7 @@
 
     // Statistics. These values will be filled when the benchmark has finished.
     // The computation needs double precision, but long int is fine for final reporting.
-    private long mMedian = 0;
-    private double mMean = 0.0;
-    private double mStandardDeviation = 0.0;
-    private long mMin = 0;
+    private Stats mStats;
 
     // Individual duration in nano seconds.
     private ArrayList<Long> mResults = new ArrayList<>();
@@ -90,36 +86,6 @@
         return TimeUnit.MILLISECONDS.toNanos(ms);
     }
 
-    /**
-     * Calculates statistics.
-     */
-    private void calculateSatistics() {
-        final int size = mResults.size();
-        if (size <= 1) {
-            throw new IllegalStateException("At least two results are necessary.");
-        }
-
-        Collections.sort(mResults);
-        mMedian = size % 2 == 0 ? (mResults.get(size / 2) + mResults.get(size / 2 + 1)) / 2 :
-                mResults.get(size / 2);
-
-        mMin = mResults.get(0);
-        for (int i = 0; i < size; ++i) {
-            long result = mResults.get(i);
-            mMean += result;
-            if (result < mMin) {
-                mMin = result;
-            }
-        }
-        mMean /= (double) size;
-
-        for (int i = 0; i < size; ++i) {
-            final double tmp = mResults.get(i) - mMean;
-            mStandardDeviation += tmp * tmp;
-        }
-        mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1));
-    }
-
     // Stops the benchmark timer.
     // This method can be called only when the timer is running.
     public void pauseTiming() {
@@ -173,7 +139,7 @@
             if (ENABLE_PROFILING) {
                 Debug.stopMethodTracing();
             }
-            calculateSatistics();
+            mStats = new Stats(mResults);
             mState = FINISHED;
             return false;
         }
@@ -224,28 +190,28 @@
         if (mState != FINISHED) {
             throw new IllegalStateException("The benchmark hasn't finished");
         }
-        return (long) mMean;
+        return (long) mStats.getMean();
     }
 
     private long median() {
         if (mState != FINISHED) {
             throw new IllegalStateException("The benchmark hasn't finished");
         }
-        return mMedian;
+        return mStats.getMedian();
     }
 
     private long min() {
         if (mState != FINISHED) {
             throw new IllegalStateException("The benchmark hasn't finished");
         }
-        return mMin;
+        return mStats.getMin();
     }
 
     private long standardDeviation() {
         if (mState != FINISHED) {
             throw new IllegalStateException("The benchmark hasn't finished");
         }
-        return (long) mStandardDeviation;
+        return (long) mStats.getStandardDeviation();
     }
 
     private String summaryLine() {
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
new file mode 100644
index 0000000..2c84db1
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.perftests.utils;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides a benchmark framework.
+ *
+ * This differs from BenchmarkState in that rather than the class measuring the the elapsed time,
+ * the test passes in the elapsed time.
+ *
+ * Example usage:
+ *
+ * public void sampleMethod() {
+ *     ManualBenchmarkState state = new ManualBenchmarkState();
+ *
+ *     int[] src = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+ *     long elapsedTime = 0;
+ *     while (state.keepRunning(elapsedTime)) {
+ *         long startTime = System.nanoTime();
+ *         int[] dest = new int[src.length];
+ *         System.arraycopy(src, 0, dest, 0, src.length);
+ *         elapsedTime = System.nanoTime() - startTime;
+ *     }
+ *     System.out.println(state.summaryLine());
+ * }
+ *
+ * Or use the PerfManualStatusReporter TestRule.
+ *
+ * Make sure that the overhead of checking the clock does not noticeably affect the results.
+ */
+public final class ManualBenchmarkState {
+    private static final String TAG = ManualBenchmarkState.class.getSimpleName();
+
+    // TODO: Tune these values.
+    // warm-up for duration
+    private static final long WARMUP_DURATION_NS = TimeUnit.SECONDS.toNanos(5);
+    // minimum iterations to warm-up for
+    private static final int WARMUP_MIN_ITERATIONS = 8;
+
+    // target testing for duration
+    private static final long TARGET_TEST_DURATION_NS = TimeUnit.SECONDS.toNanos(16);
+    private static final int MAX_TEST_ITERATIONS = 1000000;
+    private static final int MIN_TEST_ITERATIONS = 10;
+
+    private static final int NOT_STARTED = 0;  // The benchmark has not started yet.
+    private static final int WARMUP = 1; // The benchmark is warming up.
+    private static final int RUNNING = 2;  // The benchmark is running.
+    private static final int FINISHED = 3;  // The benchmark has stopped.
+
+    private int mState = NOT_STARTED;  // Current benchmark state.
+
+    private long mWarmupStartTime = 0;
+    private int mWarmupIterations = 0;
+
+    private int mMaxIterations = 0;
+
+    // Individual duration in nano seconds.
+    private ArrayList<Long> mResults = new ArrayList<>();
+
+    // Statistics. These values will be filled when the benchmark has finished.
+    // The computation needs double precision, but long int is fine for final reporting.
+    private Stats mStats;
+
+    private void beginBenchmark(long warmupDuration, int iterations) {
+        mMaxIterations = (int) (TARGET_TEST_DURATION_NS / (warmupDuration / iterations));
+        mMaxIterations = Math.min(MAX_TEST_ITERATIONS,
+                Math.max(mMaxIterations, MIN_TEST_ITERATIONS));
+        mState = RUNNING;
+    }
+
+    /**
+     * Judges whether the benchmark needs more samples.
+     *
+     * For the usage, see class comment.
+     */
+    public boolean keepRunning(long duration) {
+        if (duration < 0) {
+            throw new RuntimeException("duration is negative: " + duration);
+        }
+        switch (mState) {
+            case NOT_STARTED:
+                mState = WARMUP;
+                mWarmupStartTime = System.nanoTime();
+                return true;
+            case WARMUP: {
+                final long timeSinceStartingWarmup = System.nanoTime() - mWarmupStartTime;
+                ++mWarmupIterations;
+                if (mWarmupIterations >= WARMUP_MIN_ITERATIONS
+                        && timeSinceStartingWarmup >= WARMUP_DURATION_NS) {
+                    beginBenchmark(timeSinceStartingWarmup, mWarmupIterations);
+                }
+                return true;
+            }
+            case RUNNING: {
+                mResults.add(duration);
+                final boolean keepRunning = mResults.size() < mMaxIterations;
+                if (!keepRunning) {
+                    mStats = new Stats(mResults);
+                    mState = FINISHED;
+                }
+                return keepRunning;
+            }
+            case FINISHED:
+                throw new IllegalStateException("The benchmark has finished.");
+            default:
+                throw new IllegalStateException("The benchmark is in an unknown state.");
+        }
+    }
+
+    private String summaryLine() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("Summary: ");
+        sb.append("median=").append(mStats.getMedian()).append("ns, ");
+        sb.append("mean=").append(mStats.getMean()).append("ns, ");
+        sb.append("min=").append(mStats.getMin()).append("ns, ");
+        sb.append("max=").append(mStats.getMax()).append("ns, ");
+        sb.append("sigma=").append(mStats.getStandardDeviation()).append(", ");
+        sb.append("iteration=").append(mResults.size()).append(", ");
+        sb.append("values=").append(mResults.toString());
+        return sb.toString();
+    }
+
+    public void sendFullStatusReport(Instrumentation instrumentation, String key) {
+        if (mState != FINISHED) {
+            throw new IllegalStateException("The benchmark hasn't finished");
+        }
+        Log.i(TAG, key + summaryLine());
+        final Bundle status = new Bundle();
+        status.putLong(key + "_median", mStats.getMedian());
+        status.putLong(key + "_mean", (long) mStats.getMean());
+        status.putLong(key + "_stddev", (long) mStats.getStandardDeviation());
+        instrumentation.sendStatus(Activity.RESULT_OK, status);
+    }
+}
+
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
new file mode 100644
index 0000000..0de6f1d
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.perftests.utils;
+
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Use this rule to make sure we report the status after the test success.
+ *
+ * <code>
+ *
+ * @Rule public PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
+ * @Test public void functionName() {
+ *     ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ *
+ *     int[] src = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+ *     long elapsedTime = 0;
+ *     while (state.keepRunning(elapsedTime)) {
+ *         long startTime = System.nanoTime();
+ *         int[] dest = new int[src.length];
+ *         System.arraycopy(src, 0, dest, 0, src.length);
+ *         elapsedTime = System.nanoTime() - startTime;
+ *     }
+ * }
+ * </code>
+ *
+ * When test succeeded, the status report will use the key as
+ * "functionName_*"
+ */
+
+public class PerfManualStatusReporter implements TestRule {
+    private final ManualBenchmarkState mState;
+
+    public PerfManualStatusReporter() {
+        mState = new ManualBenchmarkState();
+    }
+
+    public ManualBenchmarkState getBenchmarkState() {
+        return mState;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                base.evaluate();
+
+                mState.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(),
+                        description.getMethodName());
+            }
+        };
+    }
+}
+
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java b/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java
new file mode 100644
index 0000000..acc44a8
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.perftests.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Stats {
+    private long mMedian, mMin, mMax;
+    private double mMean, mStandardDeviation;
+
+    /* Calculate stats in constructor. */
+    public Stats(List<Long> values) {
+        // make a copy since we're modifying it
+        values = new ArrayList<>(values);
+        final int size = values.size();
+        if (size < 2) {
+            throw new IllegalArgumentException("At least two results are necessary.");
+        }
+
+        Collections.sort(values);
+
+        mMedian = size % 2 == 0 ? (values.get(size / 2) + values.get(size / 2 - 1)) / 2 :
+                values.get(size / 2);
+
+        mMin = values.get(0);
+        mMax = values.get(values.size() - 1);
+
+        for (int i = 0; i < size; ++i) {
+            long result = values.get(i);
+            mMean += result;
+        }
+        mMean /= (double) size;
+
+        for (int i = 0; i < size; ++i) {
+            final double tmp = values.get(i) - mMean;
+            mStandardDeviation += tmp * tmp;
+        }
+        mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1));
+    }
+
+    public double getMean() {
+        return mMean;
+    }
+
+    public long getMedian() {
+        return mMedian;
+    }
+
+    public long getMax() {
+        return mMax;
+    }
+
+    public long getMin() {
+        return mMin;
+    }
+
+    public double getStandardDeviation() {
+        return mStandardDeviation;
+    }
+}
diff --git a/api/current.txt b/api/current.txt
index 1cebc28..c9c9e01 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -212,6 +212,7 @@
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
     field public static final int accessibilityFlags = 16843652; // 0x1010384
     field public static final int accessibilityLiveRegion = 16843758; // 0x10103ee
+    field public static final int accessibilityPaneTitle = 16844156; // 0x101057c
     field public static final int accessibilityTraversalAfter = 16843986; // 0x10104d2
     field public static final int accessibilityTraversalBefore = 16843985; // 0x10104d1
     field public static final int accountPreferences = 16843423; // 0x101029f
@@ -5206,15 +5207,17 @@
     field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
     field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession";
     field public static final java.lang.String EXTRA_MESSAGES = "android.messages";
+    field public static final java.lang.String EXTRA_MESSAGING_PERSON = "android.messagingUser";
     field public static final java.lang.String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
     field public static final java.lang.String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
-    field public static final java.lang.String EXTRA_PEOPLE = "android.people";
+    field public static final deprecated java.lang.String EXTRA_PEOPLE = "android.people";
+    field public static final java.lang.String EXTRA_PEOPLE_LIST = "android.people.list";
     field public static final java.lang.String EXTRA_PICTURE = "android.picture";
     field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
     field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
     field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
     field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
-    field public static final java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+    field public static final deprecated java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
     field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
     field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
     field public static final deprecated java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5288,8 +5291,19 @@
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.RemoteInput[] getRemoteInputs();
+    method public int getSemanticAction();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR;
+    field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+    field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+    field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+    field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+    field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+    field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+    field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+    field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+    field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+    field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
     field public android.app.PendingIntent actionIntent;
     field public deprecated int icon;
     field public java.lang.CharSequence title;
@@ -5305,6 +5319,7 @@
     method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
     method public android.os.Bundle getExtras();
     method public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
+    method public android.app.Notification.Action.Builder setSemanticAction(int);
   }
 
   public static abstract interface Notification.Action.Extender {
@@ -5354,7 +5369,8 @@
     method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.Notification.Builder addAction(android.app.Notification.Action);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
-    method public android.app.Notification.Builder addPerson(java.lang.String);
+    method public deprecated android.app.Notification.Builder addPerson(java.lang.String);
+    method public android.app.Notification.Builder addPerson(android.app.Notification.Person);
     method public android.app.Notification build();
     method public android.widget.RemoteViews createBigContentView();
     method public android.widget.RemoteViews createContentView();
@@ -5477,14 +5493,17 @@
   }
 
   public static class Notification.MessagingStyle extends android.app.Notification.Style {
-    ctor public Notification.MessagingStyle(java.lang.CharSequence);
+    ctor public deprecated Notification.MessagingStyle(java.lang.CharSequence);
+    ctor public Notification.MessagingStyle(android.app.Notification.Person);
     method public android.app.Notification.MessagingStyle addHistoricMessage(android.app.Notification.MessagingStyle.Message);
-    method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence);
+    method public deprecated android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence);
+    method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, android.app.Notification.Person);
     method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message);
     method public java.lang.CharSequence getConversationTitle();
     method public java.util.List<android.app.Notification.MessagingStyle.Message> getHistoricMessages();
     method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages();
-    method public java.lang.CharSequence getUserDisplayName();
+    method public android.app.Notification.Person getUser();
+    method public deprecated java.lang.CharSequence getUserDisplayName();
     method public boolean isGroupConversation();
     method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence);
     method public android.app.Notification.MessagingStyle setGroupConversation(boolean);
@@ -5492,16 +5511,34 @@
   }
 
   public static final class Notification.MessagingStyle.Message {
-    ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
+    ctor public deprecated Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
+    ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, android.app.Notification.Person);
     method public java.lang.String getDataMimeType();
     method public android.net.Uri getDataUri();
     method public android.os.Bundle getExtras();
-    method public java.lang.CharSequence getSender();
+    method public deprecated java.lang.CharSequence getSender();
+    method public android.app.Notification.Person getSenderPerson();
     method public java.lang.CharSequence getText();
     method public long getTimestamp();
     method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
   }
 
+  public static final class Notification.Person implements android.os.Parcelable {
+    ctor protected Notification.Person(android.os.Parcel);
+    ctor public Notification.Person();
+    method public int describeContents();
+    method public android.graphics.drawable.Icon getIcon();
+    method public java.lang.String getKey();
+    method public java.lang.CharSequence getName();
+    method public java.lang.String getUri();
+    method public android.app.Notification.Person setIcon(android.graphics.drawable.Icon);
+    method public android.app.Notification.Person setKey(java.lang.String);
+    method public android.app.Notification.Person setName(java.lang.CharSequence);
+    method public android.app.Notification.Person setUri(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.Notification.Person> CREATOR;
+  }
+
   public static abstract class Notification.Style {
     ctor public Notification.Style();
     method public android.app.Notification build();
@@ -6298,6 +6335,7 @@
     method public void onReceive(android.content.Context, android.content.Intent);
     method public void onSecurityLogsAvailable(android.content.Context, android.content.Intent);
     method public void onSystemUpdatePending(android.content.Context, android.content.Intent, long);
+    method public void onTransferOwnershipComplete(android.content.Context, android.os.PersistableBundle);
     method public void onUserAdded(android.content.Context, android.content.Intent, android.os.UserHandle);
     method public void onUserRemoved(android.content.Context, android.content.Intent, android.os.UserHandle);
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
@@ -6315,6 +6353,7 @@
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
+    field public static final java.lang.String EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE = "android.app.extra.TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE";
   }
 
   public class DeviceAdminService extends android.app.Service {
@@ -6364,6 +6403,7 @@
     method public int getLockTaskFeatures(android.content.ComponentName);
     method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
     method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
+    method public android.content.ComponentName getMandatoryBackupTransport();
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
@@ -6463,6 +6503,7 @@
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
     method public void setLogoutEnabled(android.content.ComponentName, boolean);
     method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
+    method public void setMandatoryBackupTransport(android.content.ComponentName, android.content.ComponentName);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -6505,8 +6546,10 @@
     method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
+    method public boolean startUserInBackground(android.content.ComponentName, android.os.UserHandle);
     method public boolean stopUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
+    method public void transferOwnership(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
@@ -6516,6 +6559,7 @@
     field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
     field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+    field public static final java.lang.String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
     field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
@@ -6615,7 +6659,6 @@
     field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
     field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
-    field public static final int START_USER_IN_BACKGROUND = 8; // 0x8
     field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
@@ -20841,7 +20884,6 @@
     method public int getMaxWidth();
     method public java.lang.CharSequence getTextForImeAction(int);
     method public android.app.Dialog getWindow();
-    method public void hideSoftInputFromInputMethod(int);
     method public void hideStatusIcon();
     method public void hideWindow();
     method public boolean isExtractViewShown();
@@ -20889,6 +20931,7 @@
     method public void onWindowHidden();
     method public void onWindowShown();
     method public void requestHideSelf(int);
+    method public void requestShowSelf(int);
     method public boolean sendDefaultEditorAction(boolean);
     method public void sendDownUpKeyEvents(int);
     method public void sendKeyChar(char);
@@ -20901,7 +20944,6 @@
     method public void setInputMethodAndSubtype(java.lang.String, android.view.inputmethod.InputMethodSubtype);
     method public void setInputView(android.view.View);
     method public boolean shouldOfferSwitchingToNextInputMethod();
-    method public void showSoftInputFromInputMethod(int);
     method public void showStatusIcon(int);
     method public void showWindow(boolean);
     method public void switchInputMethod(java.lang.String);
@@ -23182,6 +23224,7 @@
     field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
     field public static final java.lang.String KEY_MIME = "mime";
     field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
+    field public static final java.lang.String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
     field public static final java.lang.String KEY_PCM_ENCODING = "pcm-encoding";
     field public static final java.lang.String KEY_PRIORITY = "priority";
     field public static final java.lang.String KEY_PROFILE = "profile";
@@ -26298,10 +26341,10 @@
   }
 
   public final class MacAddress implements android.os.Parcelable {
-    method public int addressType();
     method public int describeContents();
     method public static android.net.MacAddress fromBytes(byte[]);
     method public static android.net.MacAddress fromString(java.lang.String);
+    method public int getAddressType();
     method public boolean isLocallyAssigned();
     method public byte[] toByteArray();
     method public java.lang.String toOuiString();
@@ -26311,7 +26354,6 @@
     field public static final int TYPE_BROADCAST = 3; // 0x3
     field public static final int TYPE_MULTICAST = 2; // 0x2
     field public static final int TYPE_UNICAST = 1; // 0x1
-    field public static final int TYPE_UNKNOWN = 0; // 0x0
   }
 
   public class MailTo {
@@ -32091,6 +32133,7 @@
   }
 
   public final class PowerManager {
+    method public int getLocationPowerSaveMode();
     method public boolean isDeviceIdleMode();
     method public boolean isIgnoringBatteryOptimizations(java.lang.String);
     method public boolean isInteractive();
@@ -32104,6 +32147,10 @@
     field public static final java.lang.String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
     field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
     field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
+    field public static final int LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2; // 0x2
+    field public static final int LOCATION_MODE_FOREGROUND_ONLY = 3; // 0x3
+    field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1
+    field public static final int LOCATION_MODE_NO_CHANGE = 0; // 0x0
     field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
     field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1
     field public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; // 0x20
@@ -32391,28 +32438,31 @@
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
     method public boolean isUserUnlocked();
     method public boolean isUserUnlocked(android.os.UserHandle);
+    method public boolean requestQuietModeEnabled(boolean, android.os.UserHandle);
     method public deprecated boolean setRestrictionsChallenge(java.lang.String);
     method public deprecated void setUserRestriction(java.lang.String, boolean);
     method public deprecated void setUserRestrictions(android.os.Bundle);
     method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     method public static boolean supportsMultipleUsers();
-    method public boolean trySetQuietModeEnabled(boolean, android.os.UserHandle);
     field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
     field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
     field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
     field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
     field public static final java.lang.String DISALLOW_AIRPLANE_MODE = "no_airplane_mode";
+    field public static final java.lang.String DISALLOW_AMBIENT_DISPLAY = "no_ambient_display";
     field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
     field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
     field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
     field public static final java.lang.String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
     field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
+    field public static final java.lang.String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
     field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
     field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
     field public static final java.lang.String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
     field public static final java.lang.String DISALLOW_CONFIG_LOCALE = "no_config_locale";
     field public static final java.lang.String DISALLOW_CONFIG_LOCATION_MODE = "no_config_location_mode";
     field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+    field public static final java.lang.String DISALLOW_CONFIG_SCREEN_TIMEOUT = "no_config_screen_timeout";
     field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
     field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
     field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
@@ -32434,6 +32484,7 @@
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
     field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
     field public static final java.lang.String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
+    field public static final java.lang.String DISALLOW_SHARE_INTO_MANAGED_PROFILE = "no_sharing_into_profile";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_SMS = "no_sms";
     field public static final java.lang.String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
@@ -36379,6 +36430,7 @@
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
     field public static final java.lang.String LAST_MODIFIED = "last_modified";
     field public static final java.lang.String MIME_TYPE = "mime_type";
+    field public static final java.lang.String NEW = "new";
     field public static final java.lang.String NUMBER = "number";
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
@@ -40734,8 +40786,13 @@
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
 
-  public final class CellIdentityCdma implements android.os.Parcelable {
+  public abstract class CellIdentity implements android.os.Parcelable {
     method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.CellIdentity> CREATOR;
+  }
+
+  public final class CellIdentityCdma extends android.telephony.CellIdentity {
     method public int getBasestationId();
     method public int getLatitude();
     method public int getLongitude();
@@ -40747,8 +40804,7 @@
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityCdma> CREATOR;
   }
 
-  public final class CellIdentityGsm implements android.os.Parcelable {
-    method public int describeContents();
+  public final class CellIdentityGsm extends android.telephony.CellIdentity {
     method public int getArfcn();
     method public int getBsic();
     method public int getCid();
@@ -40765,8 +40821,7 @@
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityGsm> CREATOR;
   }
 
-  public final class CellIdentityLte implements android.os.Parcelable {
-    method public int describeContents();
+  public final class CellIdentityLte extends android.telephony.CellIdentity {
     method public int getCi();
     method public int getEarfcn();
     method public deprecated int getMcc();
@@ -40782,8 +40837,17 @@
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityLte> CREATOR;
   }
 
-  public final class CellIdentityWcdma implements android.os.Parcelable {
-    method public int describeContents();
+  public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
+    method public int getCid();
+    method public int getCpid();
+    method public int getLac();
+    method public java.lang.String getMccStr();
+    method public java.lang.String getMncStr();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityTdscdma> CREATOR;
+  }
+
+  public final class CellIdentityWcdma extends android.telephony.CellIdentity {
     method public int getCid();
     method public int getLac();
     method public deprecated int getMcc();
@@ -41084,6 +41148,7 @@
     method public void onServiceStateChanged(android.telephony.ServiceState);
     method public deprecated void onSignalStrengthChanged(int);
     method public void onSignalStrengthsChanged(android.telephony.SignalStrength);
+    method public void onUserMobileDataStateChanged(boolean);
     field public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
     field public static final int LISTEN_CALL_STATE = 32; // 0x20
     field public static final int LISTEN_CELL_INFO = 1024; // 0x400
@@ -41095,6 +41160,7 @@
     field public static final int LISTEN_SERVICE_STATE = 1; // 0x1
     field public static final deprecated int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
     field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
+    field public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
   }
 
   public final class RadioAccessSpecifier implements android.os.Parcelable {
@@ -41575,6 +41641,78 @@
 
 }
 
+package android.telephony.data {
+
+  public class ApnSetting implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getApnName();
+    method public int getAuthType();
+    method public java.lang.String getEntryName();
+    method public int getId();
+    method public int getMmsPort();
+    method public java.net.InetAddress getMmsProxy();
+    method public java.net.URL getMmsc();
+    method public java.lang.String getMvnoType();
+    method public java.lang.String getOperatorNumeric();
+    method public java.lang.String getPassword();
+    method public int getPort();
+    method public java.lang.String getProtocol();
+    method public java.net.InetAddress getProxy();
+    method public java.lang.String getRoamingProtocol();
+    method public java.util.List<java.lang.String> getTypes();
+    method public java.lang.String getUser();
+    method public boolean isEnabled();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int AUTH_TYPE_CHAP = 2; // 0x2
+    field public static final int AUTH_TYPE_NONE = 0; // 0x0
+    field public static final int AUTH_TYPE_PAP = 1; // 0x1
+    field public static final int AUTH_TYPE_PAP_OR_CHAP = 3; // 0x3
+    field public static final android.os.Parcelable.Creator<android.telephony.data.ApnSetting> CREATOR;
+    field public static final java.lang.String MVNO_TYPE_GID = "gid";
+    field public static final java.lang.String MVNO_TYPE_ICCID = "iccid";
+    field public static final java.lang.String MVNO_TYPE_IMSI = "imsi";
+    field public static final java.lang.String MVNO_TYPE_SPN = "spn";
+    field public static final java.lang.String PROTOCOL_IP = "IP";
+    field public static final java.lang.String PROTOCOL_IPV4V6 = "IPV4V6";
+    field public static final java.lang.String PROTOCOL_IPV6 = "IPV6";
+    field public static final java.lang.String PROTOCOL_PPP = "PPP";
+    field public static final java.lang.String TYPE_ALL = "*";
+    field public static final java.lang.String TYPE_CBS = "cbs";
+    field public static final java.lang.String TYPE_DEFAULT = "default";
+    field public static final java.lang.String TYPE_DUN = "dun";
+    field public static final java.lang.String TYPE_EMERGENCY = "emergency";
+    field public static final java.lang.String TYPE_FOTA = "fota";
+    field public static final java.lang.String TYPE_HIPRI = "hipri";
+    field public static final java.lang.String TYPE_IA = "ia";
+    field public static final java.lang.String TYPE_IMS = "ims";
+    field public static final java.lang.String TYPE_MMS = "mms";
+    field public static final java.lang.String TYPE_SUPL = "supl";
+  }
+
+  public static class ApnSetting.Builder {
+    ctor public ApnSetting.Builder();
+    method public android.telephony.data.ApnSetting build();
+    method public android.telephony.data.ApnSetting.Builder setApnName(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setAuthType(int);
+    method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
+    method public android.telephony.data.ApnSetting.Builder setEntryName(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setId(int);
+    method public android.telephony.data.ApnSetting.Builder setMmsPort(int);
+    method public android.telephony.data.ApnSetting.Builder setMmsProxy(java.net.InetAddress);
+    method public android.telephony.data.ApnSetting.Builder setMmsc(java.net.URL);
+    method public android.telephony.data.ApnSetting.Builder setMvnoType(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setPassword(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setPort(int);
+    method public android.telephony.data.ApnSetting.Builder setProtocol(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setProxy(java.net.InetAddress);
+    method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setTypes(java.util.List<java.lang.String>);
+    method public android.telephony.data.ApnSetting.Builder setUser(java.lang.String);
+  }
+
+}
+
 package android.telephony.gsm {
 
   public class GsmCellLocation extends android.telephony.CellLocation {
@@ -42159,20 +42297,9 @@
     method public boolean isAllowed(char);
   }
 
-  public abstract interface NoCopySpan {
-  }
-
-  public static class NoCopySpan.Concrete implements android.text.NoCopySpan {
-    ctor public NoCopySpan.Concrete();
-  }
-
-  public abstract interface ParcelableSpan implements android.os.Parcelable {
-    method public abstract int getSpanTypeId();
-  }
-
-  public class PremeasuredText implements android.text.Spanned {
-    method public static android.text.PremeasuredText build(java.lang.CharSequence, android.text.TextPaint, android.text.TextDirectionHeuristic);
-    method public static android.text.PremeasuredText build(java.lang.CharSequence, android.text.TextPaint, android.text.TextDirectionHeuristic, int, int);
+  public class MeasuredText implements android.text.Spanned {
+    method public static android.text.MeasuredText build(java.lang.CharSequence, android.text.TextPaint, android.text.TextDirectionHeuristic);
+    method public static android.text.MeasuredText build(java.lang.CharSequence, android.text.TextPaint, android.text.TextDirectionHeuristic, int, int);
     method public char charAt(int);
     method public int getEnd();
     method public android.text.TextPaint getPaint();
@@ -42191,6 +42318,17 @@
     method public java.lang.CharSequence subSequence(int, int);
   }
 
+  public abstract interface NoCopySpan {
+  }
+
+  public static class NoCopySpan.Concrete implements android.text.NoCopySpan {
+    ctor public NoCopySpan.Concrete();
+  }
+
+  public abstract interface ParcelableSpan implements android.os.Parcelable {
+    method public abstract int getSpanTypeId();
+  }
+
   public class Selection {
     method public static boolean extendDown(android.text.Spannable, android.text.Layout);
     method public static boolean extendLeft(android.text.Spannable, android.text.Layout);
@@ -45131,6 +45269,7 @@
     field public static final int KEYCODE_8 = 15; // 0xf
     field public static final int KEYCODE_9 = 16; // 0x10
     field public static final int KEYCODE_A = 29; // 0x1d
+    field public static final int KEYCODE_ALL_APPS = 284; // 0x11c
     field public static final int KEYCODE_ALT_LEFT = 57; // 0x39
     field public static final int KEYCODE_ALT_RIGHT = 58; // 0x3a
     field public static final int KEYCODE_APOSTROPHE = 75; // 0x4b
@@ -46176,6 +46315,7 @@
     method public java.lang.CharSequence getAccessibilityClassName();
     method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
+    method public java.lang.CharSequence getAccessibilityPaneTitle();
     method public int getAccessibilityTraversalAfter();
     method public int getAccessibilityTraversalBefore();
     method public float getAlpha();
@@ -46499,6 +46639,7 @@
     method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
     method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
     method public void setAccessibilityLiveRegion(int);
+    method public void setAccessibilityPaneTitle(java.lang.CharSequence);
     method public void setAccessibilityTraversalAfter(int);
     method public void setAccessibilityTraversalBefore(int);
     method public void setActivated(boolean);
@@ -47749,7 +47890,6 @@
     field public static final int FIRST_APPLICATION_WINDOW = 1; // 0x1
     field public static final int FIRST_SUB_WINDOW = 1000; // 0x3e8
     field public static final int FIRST_SYSTEM_WINDOW = 2000; // 0x7d0
-    field public static final long FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA = 1L; // 0x1L
     field public static final int FLAGS_CHANGED = 4; // 0x4
     field public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 1; // 0x1
     field public static final int FLAG_ALT_FOCUSABLE_IM = 131072; // 0x20000
@@ -47787,6 +47927,9 @@
     field public static final int LAST_SUB_WINDOW = 1999; // 0x7cf
     field public static final int LAST_SYSTEM_WINDOW = 2999; // 0xbb7
     field public static final int LAYOUT_CHANGED = 1; // 0x1
+    field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; // 0x1
+    field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 0x0
+    field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2
     field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100
     field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2
     field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1
@@ -47849,6 +47992,7 @@
     field public int gravity;
     field public float horizontalMargin;
     field public float horizontalWeight;
+    field public int layoutInDisplayCutoutMode;
     field public deprecated int memoryType;
     field public java.lang.String packageName;
     field public int preferredDisplayModeId;
@@ -47896,6 +48040,9 @@
     method public void setPackageName(java.lang.CharSequence);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+    field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+    field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
     field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
     field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
     field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
@@ -48006,6 +48153,7 @@
     method public int getMaxTextLength();
     method public int getMovementGranularities();
     method public java.lang.CharSequence getPackageName();
+    method public java.lang.CharSequence getPaneTitle();
     method public android.view.accessibility.AccessibilityNodeInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo.RangeInfo getRangeInfo();
     method public java.lang.CharSequence getText();
@@ -48083,6 +48231,7 @@
     method public void setMovementGranularities(int);
     method public void setMultiLine(boolean);
     method public void setPackageName(java.lang.CharSequence);
+    method public void setPaneTitle(java.lang.CharSequence);
     method public void setParent(android.view.View);
     method public void setParent(android.view.View, int);
     method public void setPassword(boolean);
@@ -49119,14 +49268,13 @@
     method public android.graphics.drawable.Drawable getSecondaryIcon(int);
     method public android.content.Intent getSecondaryIntent(int);
     method public java.lang.CharSequence getSecondaryLabel(int);
-    method public android.view.View.OnClickListener getSecondaryOnClickListener(int);
     method public java.lang.String getSignature();
     method public java.lang.String getText();
   }
 
   public static final class TextClassification.Builder {
     ctor public TextClassification.Builder();
-    method public android.view.textclassifier.TextClassification.Builder addSecondaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
+    method public android.view.textclassifier.TextClassification.Builder addSecondaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable);
     method public android.view.textclassifier.TextClassification build();
     method public android.view.textclassifier.TextClassification.Builder clearSecondaryActions();
     method public android.view.textclassifier.TextClassification.Builder setEntityType(java.lang.String, float);
@@ -49134,15 +49282,18 @@
     method public android.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
     method public android.view.textclassifier.TextClassification.Builder setLabel(java.lang.String);
     method public android.view.textclassifier.TextClassification.Builder setOnClickListener(android.view.View.OnClickListener);
-    method public android.view.textclassifier.TextClassification.Builder setPrimaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
+    method public android.view.textclassifier.TextClassification.Builder setPrimaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable);
     method public android.view.textclassifier.TextClassification.Builder setSignature(java.lang.String);
     method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
   }
 
-  public static final class TextClassification.Options {
+  public static final class TextClassification.Options implements android.os.Parcelable {
     ctor public TextClassification.Options();
+    method public int describeContents();
     method public android.os.LocaleList getDefaultLocales();
     method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification.Options> CREATOR;
   }
 
   public final class TextClassificationManager {
@@ -49172,16 +49323,22 @@
     field public static final java.lang.String TYPE_URL = "url";
   }
 
-  public static final class TextClassifier.EntityConfig {
+  public static final class TextClassifier.EntityConfig implements android.os.Parcelable {
     ctor public TextClassifier.EntityConfig(int);
+    method public int describeContents();
     method public android.view.textclassifier.TextClassifier.EntityConfig excludeEntities(java.lang.String...);
     method public java.util.List<java.lang.String> getEntities(android.view.textclassifier.TextClassifier);
     method public android.view.textclassifier.TextClassifier.EntityConfig includeEntities(java.lang.String...);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifier.EntityConfig> CREATOR;
   }
 
-  public final class TextLinks {
+  public final class TextLinks implements android.os.Parcelable {
     method public boolean apply(android.text.SpannableString, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.text.style.ClickableSpan>);
+    method public int describeContents();
     method public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLinks> CREATOR;
   }
 
   public static final class TextLinks.Builder {
@@ -49190,21 +49347,27 @@
     method public android.view.textclassifier.TextLinks build();
   }
 
-  public static final class TextLinks.Options {
+  public static final class TextLinks.Options implements android.os.Parcelable {
     ctor public TextLinks.Options();
+    method public int describeContents();
     method public android.os.LocaleList getDefaultLocales();
     method public android.view.textclassifier.TextClassifier.EntityConfig getEntityConfig();
     method public android.view.textclassifier.TextLinks.Options setDefaultLocales(android.os.LocaleList);
     method public android.view.textclassifier.TextLinks.Options setEntityConfig(android.view.textclassifier.TextClassifier.EntityConfig);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLinks.Options> CREATOR;
   }
 
-  public static final class TextLinks.TextLink {
+  public static final class TextLinks.TextLink implements android.os.Parcelable {
     ctor public TextLinks.TextLink(java.lang.String, int, int, java.util.Map<java.lang.String, java.lang.Float>);
+    method public int describeContents();
     method public float getConfidenceScore(java.lang.String);
     method public int getEnd();
     method public java.lang.String getEntity(int);
     method public int getEntityCount();
     method public int getStart();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLinks.TextLink> CREATOR;
   }
 
   public final class TextSelection {
@@ -49223,10 +49386,13 @@
     method public android.view.textclassifier.TextSelection.Builder setSignature(java.lang.String);
   }
 
-  public static final class TextSelection.Options {
+  public static final class TextSelection.Options implements android.os.Parcelable {
     ctor public TextSelection.Options();
+    method public int describeContents();
     method public android.os.LocaleList getDefaultLocales();
     method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextSelection.Options> CREATOR;
   }
 
 }
diff --git a/api/removed.txt b/api/removed.txt
index 2aab223..77088e5 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -265,6 +265,7 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
+    method public deprecated boolean trySetQuietModeEnabled(boolean, android.os.UserHandle);
   }
 
 }
diff --git a/api/system-current.txt b/api/system-current.txt
index b2d5a49..762b6e8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -33,6 +33,7 @@
     field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
     field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
     field public static final java.lang.String BRICK = "android.permission.BRICK";
+    field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
     field public static final deprecated java.lang.String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
     field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
     field public static final java.lang.String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
@@ -46,6 +47,7 @@
     field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
     field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
     field public static final java.lang.String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
+    field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final java.lang.String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
     field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
     field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
@@ -153,6 +155,7 @@
     field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
     field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
     field public static final java.lang.String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
+    field public static final java.lang.String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS";
     field public static final java.lang.String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER";
     field public static final java.lang.String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
     field public static final java.lang.String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
@@ -161,6 +164,7 @@
     field public static final java.lang.String SET_TIME = "android.permission.SET_TIME";
     field public static final java.lang.String SET_VOLUME_KEY_LONG_PRESS_LISTENER = "android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER";
     field public static final java.lang.String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
+    field public static final java.lang.String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
     field public static final java.lang.String SHUTDOWN = "android.permission.SHUTDOWN";
     field public static final java.lang.String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
     field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
@@ -190,10 +194,6 @@
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
     field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
-    field public static final int searchKeyphrase = 16843871; // 0x101045f
-    field public static final int searchKeyphraseId = 16843870; // 0x101045e
-    field public static final int searchKeyphraseRecognitionFlags = 16843942; // 0x10104a6
-    field public static final int searchKeyphraseSupportedLocales = 16843872; // 0x1010460
   }
 
   public static final class R.raw {
@@ -315,6 +315,11 @@
     method public void onInstantAppResolveInfo(java.util.List<android.content.pm.InstantAppResolveInfo>);
   }
 
+  public class KeyguardManager {
+    method public android.content.Intent createConfirmFactoryResetCredentialIntent(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
+    method public void requestDismissKeyguard(android.app.Activity, java.lang.CharSequence, android.app.KeyguardManager.KeyguardDismissCallback);
+  }
+
   public class Notification implements android.os.Parcelable {
     field public static final java.lang.String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
     field public static final java.lang.String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
@@ -684,6 +689,9 @@
     method public boolean isEncrypted();
     method public boolean removeBond();
     method public boolean setPhonebookAccessPermission(int);
+    field public static final int ACCESS_ALLOWED = 1; // 0x1
+    field public static final int ACCESS_REJECTED = 2; // 0x2
+    field public static final int ACCESS_UNKNOWN = 0; // 0x0
   }
 
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
@@ -692,6 +700,11 @@
     method public boolean setPriority(android.bluetooth.BluetoothDevice, int);
   }
 
+  public abstract interface BluetoothProfile {
+    field public static final int PRIORITY_OFF = 0; // 0x0
+    field public static final int PRIORITY_ON = 100; // 0x64
+  }
+
 }
 
 package android.bluetooth.le {
@@ -896,6 +909,7 @@
     method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
     method public android.content.pm.dex.ArtManager getArtManager();
     method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
+    method public java.lang.CharSequence getHarmfulAppWarning(java.lang.String);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
     method public abstract android.content.ComponentName getInstantAppInstallerComponent();
@@ -912,6 +926,7 @@
     method public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
+    method public void setHarmfulAppWarning(java.lang.String, java.lang.CharSequence);
     method public abstract void setUpdateAvailable(java.lang.String, boolean);
     method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
     method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
@@ -1079,8 +1094,38 @@
 
 package android.hardware.display {
 
+  public final class BrightnessChangeEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessChangeEvent> CREATOR;
+    field public final float batteryLevel;
+    field public final float brightness;
+    field public final int colorTemperature;
+    field public final float lastBrightness;
+    field public final long[] luxTimestamps;
+    field public final float[] luxValues;
+    field public final boolean nightMode;
+    field public final java.lang.String packageName;
+    field public final long timeStamp;
+  }
+
+  public final class BrightnessConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.util.Pair<float[], float[]> getCurve();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
+  }
+
+  public static class BrightnessConfiguration.Builder {
+    ctor public BrightnessConfiguration.Builder();
+    method public android.hardware.display.BrightnessConfiguration build();
+    method public android.hardware.display.BrightnessConfiguration.Builder setCurve(float[], float[]);
+  }
+
   public final class DisplayManager {
+    method public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
     method public android.graphics.Point getStableDisplaySize();
+    method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
   }
 
 }
@@ -1688,6 +1733,39 @@
 
 package android.hardware.radio {
 
+  public final class ProgramList implements java.lang.AutoCloseable {
+    method public void addOnCompleteListener(java.util.concurrent.Executor, android.hardware.radio.ProgramList.OnCompleteListener);
+    method public void addOnCompleteListener(android.hardware.radio.ProgramList.OnCompleteListener);
+    method public void close();
+    method public android.hardware.radio.RadioManager.ProgramInfo get(android.hardware.radio.ProgramSelector.Identifier);
+    method public void registerListCallback(java.util.concurrent.Executor, android.hardware.radio.ProgramList.ListCallback);
+    method public void registerListCallback(android.hardware.radio.ProgramList.ListCallback);
+    method public void removeOnCompleteListener(android.hardware.radio.ProgramList.OnCompleteListener);
+    method public java.util.List<android.hardware.radio.RadioManager.ProgramInfo> toList();
+    method public void unregisterListCallback(android.hardware.radio.ProgramList.ListCallback);
+  }
+
+  public static final class ProgramList.Filter implements android.os.Parcelable {
+    ctor public ProgramList.Filter(java.util.Set<java.lang.Integer>, java.util.Set<android.hardware.radio.ProgramSelector.Identifier>, boolean, boolean);
+    method public boolean areCategoriesIncluded();
+    method public boolean areModificationsExcluded();
+    method public int describeContents();
+    method public java.util.Set<java.lang.Integer> getIdentifierTypes();
+    method public java.util.Set<android.hardware.radio.ProgramSelector.Identifier> getIdentifiers();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramList.Filter> CREATOR;
+  }
+
+  public static abstract class ProgramList.ListCallback {
+    ctor public ProgramList.ListCallback();
+    method public void onItemChanged(android.hardware.radio.ProgramSelector.Identifier);
+    method public void onItemRemoved(android.hardware.radio.ProgramSelector.Identifier);
+  }
+
+  public static abstract interface ProgramList.OnCompleteListener {
+    method public abstract void onComplete();
+  }
+
   public final class ProgramSelector implements android.os.Parcelable {
     ctor public ProgramSelector(int, android.hardware.radio.ProgramSelector.Identifier, android.hardware.radio.ProgramSelector.Identifier[], long[]);
     method public static android.hardware.radio.ProgramSelector createAmFmSelector(int, int);
@@ -1711,6 +1789,7 @@
     field public static final int IDENTIFIER_TYPE_DRMO_SERVICE_ID = 9; // 0x9
     field public static final int IDENTIFIER_TYPE_HD_STATION_ID_EXT = 3; // 0x3
     field public static final int IDENTIFIER_TYPE_HD_SUBCHANNEL = 4; // 0x4
+    field public static final int IDENTIFIER_TYPE_INVALID = 0; // 0x0
     field public static final int IDENTIFIER_TYPE_RDS_PI = 2; // 0x2
     field public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13; // 0xd
     field public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12; // 0xc
@@ -1722,6 +1801,7 @@
     field public static final int PROGRAM_TYPE_DRMO = 6; // 0x6
     field public static final int PROGRAM_TYPE_FM = 2; // 0x2
     field public static final int PROGRAM_TYPE_FM_HD = 4; // 0x4
+    field public static final int PROGRAM_TYPE_INVALID = 0; // 0x0
     field public static final int PROGRAM_TYPE_SXM = 7; // 0x7
     field public static final int PROGRAM_TYPE_VENDOR_END = 1999; // 0x7cf
     field public static final int PROGRAM_TYPE_VENDOR_START = 1000; // 0x3e8
@@ -1940,10 +2020,11 @@
     method public abstract void cancelAnnouncement();
     method public abstract void close();
     method public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
+    method public android.hardware.radio.ProgramList getDynamicProgramList(android.hardware.radio.ProgramList.Filter);
     method public abstract boolean getMute();
     method public java.util.Map<java.lang.String, java.lang.String> getParameters(java.util.List<java.lang.String>);
     method public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
-    method public abstract java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(java.util.Map<java.lang.String, java.lang.String>);
+    method public abstract deprecated java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(java.util.Map<java.lang.String, java.lang.String>);
     method public abstract boolean hasControl();
     method public abstract deprecated boolean isAnalogForced();
     method public abstract boolean isAntennaConnected();
@@ -3991,6 +4072,7 @@
     method public final void removeEscrowToken(long, android.os.UserHandle);
     method public final void revokeTrust();
     method public final void setManagingTrust(boolean);
+    method public final void showKeyguardErrorMessage(java.lang.CharSequence);
     method public final void unlockUserWithToken(long, byte[], android.os.UserHandle);
     field public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 2; // 0x2
     field public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1; // 0x1
@@ -4275,6 +4357,7 @@
     method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
     method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
     field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
+    field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
   }
 
   public final class SubscriptionPlan implements android.os.Parcelable {
@@ -4371,6 +4454,8 @@
     method public deprecated void setDataEnabled(int, boolean);
     method public boolean setRadio(boolean);
     method public boolean setRadioPower(boolean);
+    method public void setSimPowerState(int);
+    method public void setSimPowerStateForSlot(int, int);
     method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
     method public void setVoiceActivationState(int);
     method public deprecated void silenceRinger();
@@ -4403,11 +4488,11 @@
 package android.telephony.data {
 
   public final class DataCallResponse implements android.os.Parcelable {
-    ctor public DataCallResponse(int, int, int, int, java.lang.String, java.lang.String, java.util.List<android.telephony.data.InterfaceAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.lang.String>, int);
+    ctor public DataCallResponse(int, int, int, int, java.lang.String, java.lang.String, java.util.List<android.net.LinkAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.lang.String>, int);
     ctor public DataCallResponse(android.os.Parcel);
     method public int describeContents();
     method public int getActive();
-    method public java.util.List<android.telephony.data.InterfaceAddress> getAddresses();
+    method public java.util.List<android.net.LinkAddress> getAddresses();
     method public int getCallId();
     method public java.util.List<java.net.InetAddress> getDnses();
     method public java.util.List<java.net.InetAddress> getGateways();
@@ -4450,17 +4535,6 @@
     field public static final int TYPE_COMMON = 0; // 0x0
   }
 
-  public final class InterfaceAddress implements android.os.Parcelable {
-    ctor public InterfaceAddress(java.net.InetAddress, int);
-    ctor public InterfaceAddress(java.lang.String, int) throws java.net.UnknownHostException;
-    ctor public InterfaceAddress(android.os.Parcel);
-    method public int describeContents();
-    method public java.net.InetAddress getAddress();
-    method public int getNetworkPrefixLength();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.data.InterfaceAddress> CREATOR;
-  }
-
 }
 
 package android.telephony.ims {
@@ -4573,9 +4647,12 @@
   }
 
   public final class StatsManager {
+    method public boolean addConfiguration(java.lang.String, byte[], java.lang.String, java.lang.String);
     method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String);
+    method public byte[] getData(java.lang.String);
     method public byte[] getData(long);
     method public byte[] getMetadata();
+    method public boolean removeConfiguration(java.lang.String);
     method public boolean removeConfiguration(long);
   }
 
diff --git a/api/system-removed.txt b/api/system-removed.txt
index a3bf576..b63703d 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -126,25 +126,6 @@
     field public boolean untrusted;
   }
 
-  public class WifiConnectionStatistics implements android.os.Parcelable {
-    ctor public WifiConnectionStatistics();
-    ctor public WifiConnectionStatistics(android.net.wifi.WifiConnectionStatistics);
-    method public int describeContents();
-    method public void incrementOrAddUntrusted(java.lang.String, int, int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.wifi.WifiConnectionStatistics> CREATOR;
-    field public int num24GhzConnected;
-    field public int num5GhzConnected;
-    field public int numAutoJoinAttempt;
-    field public int numAutoRoamAttempt;
-    field public int numWifiManagerJoinAttempt;
-    field public java.util.HashMap<java.lang.String, android.net.wifi.WifiNetworkConnectionStatistics> untrustedNetworkHistory;
-  }
-
-  public class WifiManager {
-    method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
-  }
-
 }
 
 package android.os {
diff --git a/api/test-current.txt b/api/test-current.txt
index b16e700..6941731 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -156,6 +156,7 @@
     method public boolean isDeviceManaged();
     field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
     field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
+    field public static final java.lang.String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
     field public static final java.lang.String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
   }
 
@@ -294,6 +295,43 @@
 
 }
 
+package android.hardware.display {
+
+  public final class BrightnessChangeEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessChangeEvent> CREATOR;
+    field public final float batteryLevel;
+    field public final float brightness;
+    field public final int colorTemperature;
+    field public final float lastBrightness;
+    field public final long[] luxTimestamps;
+    field public final float[] luxValues;
+    field public final boolean nightMode;
+    field public final java.lang.String packageName;
+    field public final long timeStamp;
+  }
+
+  public final class BrightnessConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.util.Pair<float[], float[]> getCurve();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
+  }
+
+  public static class BrightnessConfiguration.Builder {
+    ctor public BrightnessConfiguration.Builder();
+    method public android.hardware.display.BrightnessConfiguration build();
+    method public android.hardware.display.BrightnessConfiguration.Builder setCurve(float[], float[]);
+  }
+
+  public final class DisplayManager {
+    method public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
+    method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+  }
+
+}
+
 package android.location {
 
   public final class GnssClock implements android.os.Parcelable {
@@ -483,6 +521,7 @@
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
+    field public static final java.lang.String LOW_POWER_MODE = "low_power";
     field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
   }
 
diff --git a/cmds/incidentd/incidentd.rc b/cmds/incidentd/incidentd.rc
index fe38a71..66667dc 100644
--- a/cmds/incidentd/incidentd.rc
+++ b/cmds/incidentd/incidentd.rc
@@ -14,6 +14,8 @@
 
 service incidentd /system/bin/incidentd
     class main
+    user incidentd
+    group incidentd log
 
 on post-fs-data
     # Create directory for incidentd
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index ffe652f..2c35d41 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -186,7 +186,8 @@
     tests/statsd_test_util.cpp \
     tests/e2e/WakelockDuration_e2e_test.cpp \
     tests/e2e/MetricConditionLink_e2e_test.cpp \
-    tests/e2e/Attribution_e2e_test.cpp
+    tests/e2e/Attribution_e2e_test.cpp \
+    tests/e2e/GaugeMetric_e2e_test.cpp
 
 LOCAL_STATIC_LIBRARIES := \
     $(statsd_common_static_libraries) \
@@ -198,6 +199,24 @@
 
 include $(BUILD_NATIVE_TEST)
 
+##############################
+# stats proto static java lib
+##############################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := statsdprotolite
+
+LOCAL_SRC_FILES := \
+    src/stats_log.proto \
+    src/statsd_config.proto \
+    src/atoms.proto
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    platformprotoslite
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
 
 statsd_common_src:=
 statsd_common_aidl_includes:=
@@ -208,4 +227,4 @@
 
 ##############################
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index a9e0f23..9d6d8a1 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -25,6 +25,8 @@
 #include "guardrail/StatsdStats.h"
 #include "metrics/CountMetricProducer.h"
 #include "external/StatsPullerManager.h"
+#include "dimension.h"
+#include "field_util.h"
 #include "stats_util.h"
 #include "storage/StorageManager.h"
 
@@ -88,30 +90,56 @@
     }
 }
 
-// TODO: what if statsd service restarts? How do we know what logs are already processed before?
-void StatsLogProcessor::OnLogEvent(const LogEvent& msg) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-
-    StatsdStats::getInstance().noteAtomLogged(msg.GetTagId(), msg.GetTimestampNs() / NS_PER_SEC);
-    // pass the event to metrics managers.
-    for (auto& pair : mMetricsManagers) {
-        pair.second->onLogEvent(msg);
-        flushIfNecessaryLocked(msg.GetTimestampNs(), pair.first, *(pair.second));
+void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const {
+    std::vector<Field> uidFields;
+    findFields(
+        event->getFieldValueMap(),
+        buildAttributionUidFieldMatcher(event->GetTagId(), Position::ANY),
+        &uidFields);
+    for (size_t i = 0; i < uidFields.size(); ++i) {
+        DimensionsValue* value = event->findFieldValueOrNull(uidFields[i]);
+        if (value != nullptr && value->value_case() == DimensionsValue::ValueCase::kValueInt) {
+            const int uid = mUidMap->getHostUidOrSelf(value->value_int());
+            value->set_value_int(uid);
+        }
     }
+}
+
+void StatsLogProcessor::onIsolatedUidChangedEventLocked(const LogEvent& event) {
+    status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR;
+    bool is_create = event.GetBool(3, &err);
+    auto parent_uid = int(event.GetLong(1, &err2));
+    auto isolated_uid = int(event.GetLong(2, &err3));
+    if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) {
+        if (is_create) {
+            mUidMap->assignIsolatedUid(isolated_uid, parent_uid);
+        } else {
+            mUidMap->removeIsolatedUid(isolated_uid, parent_uid);
+        }
+    } else {
+        ALOGE("Failed to parse uid in the isolated uid change event.");
+    }
+}
+
+// TODO: what if statsd service restarts? How do we know what logs are already processed before?
+void StatsLogProcessor::OnLogEvent(LogEvent* event) {
+    std::lock_guard<std::mutex> lock(mMetricsMutex);
+    StatsdStats::getInstance().noteAtomLogged(
+        event->GetTagId(), event->GetTimestampNs() / NS_PER_SEC);
+
     // Hard-coded logic to update the isolated uid's in the uid-map.
     // The field numbers need to be currently updated by hand with atoms.proto
-    if (msg.GetTagId() == android::util::ISOLATED_UID_CHANGED) {
-        status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR;
-        bool is_create = msg.GetBool(3, &err);
-        auto parent_uid = int(msg.GetLong(1, &err2));
-        auto isolated_uid = int(msg.GetLong(2, &err3));
-        if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) {
-            if (is_create) {
-                mUidMap->assignIsolatedUid(isolated_uid, parent_uid);
-            } else {
-                mUidMap->removeIsolatedUid(isolated_uid, parent_uid);
-            }
-        }
+    if (event->GetTagId() == android::util::ISOLATED_UID_CHANGED) {
+        onIsolatedUidChangedEventLocked(*event);
+    } else {
+        // Map the isolated uid to host uid if necessary.
+        mapIsolatedUidToHostUidIfNecessaryLocked(event);
+    }
+
+    // pass the event to metrics managers.
+    for (auto& pair : mMetricsManagers) {
+        pair.second->onLogEvent(*event);
+        flushIfNecessaryLocked(event->GetTimestampNs(), pair.first, *(pair.second));
     }
 }
 
@@ -273,7 +301,6 @@
 }
 
 void StatsLogProcessor::WriteDataToDisk() {
-    mkdir(STATS_DATA_DIR, S_IRWXU);
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     for (auto& pair : mMetricsManagers) {
         const ConfigKey& key = pair.first;
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index adc9161..301e3a5 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -38,7 +38,7 @@
                       const std::function<void(const ConfigKey&)>& sendBroadcast);
     virtual ~StatsLogProcessor();
 
-    void OnLogEvent(const LogEvent& event);
+    void OnLogEvent(LogEvent* event);
 
     void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
     void OnConfigRemoved(const ConfigKey& key);
@@ -46,7 +46,8 @@
     size_t GetMetricsSize(const ConfigKey& key) const;
 
     void onDumpReport(const ConfigKey& key, vector<uint8_t>* outData);
-    void onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs, ConfigMetricsReportList* report);
+    void onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs,
+                      ConfigMetricsReportList* report);
 
     /* Tells MetricsManager that the alarms in anomalySet have fired. Modifies anomalySet. */
     void onAnomalyAlarmFired(
@@ -79,6 +80,12 @@
     void flushIfNecessaryLocked(uint64_t timestampNs, const ConfigKey& key,
                                 MetricsManager& metricsManager);
 
+    // Maps the isolated uid in the log event to host uid if the log event contains uid fields.
+    void mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const;
+
+    // Handler over the isolated uid change event.
+    void onIsolatedUidChangedEventLocked(const LogEvent& event);
+
     // Function used to send a broadcast so that receiver for the config key can call getData
     // to retrieve the stored data.
     std::function<void(const ConfigKey& key)> mSendBroadcast;
@@ -92,6 +99,7 @@
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
+    FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
 
 };
 
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 45f1ea1..0ed1c1f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -695,7 +695,7 @@
     mConfigManager->Startup();
 }
 
-void StatsService::OnLogEvent(const LogEvent& event) {
+void StatsService::OnLogEvent(LogEvent* event) {
     mProcessor->OnLogEvent(event);
 }
 
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index c0424f3..8d29970 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -72,7 +72,7 @@
     /**
      * Called by LogReader when there's a log event to process.
      */
-    virtual void OnLogEvent(const LogEvent& event);
+    virtual void OnLogEvent(LogEvent* event);
 
     /**
      * Binder call for clients to request data for this configuration key.
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7f77ef7..4a7f0c4 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -102,7 +102,6 @@
         CpuTimePerUidFreq cpu_time_per_uid_freq = 10010;
         WifiActivityEnergyInfo wifi_activity_energy_info = 10011;
         ModemActivityInfo modem_activity_info = 10012;
-        AttributionChainDummyAtom attribution_chain_dummy_atom = 100000;
     }
 }
 
@@ -147,11 +146,6 @@
  * *****************************************************************************
  */
 
-message AttributionChainDummyAtom {
-    repeated AttributionNode attribution_node = 1;
-    optional int32 value = 2;
-}
-
 /**
  * Logs when the screen state changes.
  *
@@ -218,8 +212,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message BleScanStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -236,8 +229,7 @@
  */
 // TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
 message BleUnoptimizedScanStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -254,8 +246,7 @@
  */
 // TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
 message BleScanResultReceived {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     // Number of ble scan results returned.
     optional int32 num_of_results = 2;
@@ -268,8 +259,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message SensorStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     // TODO: Is there a way to get the actual name of the sensor?
     // The id (int) of the sensor.
@@ -290,8 +280,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message GpsScanStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -308,8 +297,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message SyncStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     // Name of the sync (as named in the app)
     optional string name = 2;
@@ -328,8 +316,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message ScheduledJobStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     // Name of the job (as named in the app)
     optional string name = 2;
@@ -350,8 +337,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message AudioStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -367,8 +353,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message MediaCodecActivityChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -384,8 +369,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message FlashlightStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -401,8 +385,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message CameraStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -447,8 +430,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message LongPartialWakelockStateChanged {
-    // TODO: Add attribution instead of uid?
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
     optional string tag = 2;
@@ -605,8 +587,7 @@
  *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
  */
 message WakeupAlarmOccurred {
-    // TODO: Add attribution instead of uid?
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     // Name of the wakeup alarm.
     optional string tag = 2;
@@ -673,8 +654,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message WifiLockStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -708,8 +688,7 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message WifiScanStateChanged {
-    // TODO: Add attribution instead of uid.
-    optional int32 uid = 1;
+    repeated AttributionNode attribution_node = 1;
 
     enum State {
         OFF = 0;
@@ -1109,14 +1088,10 @@
 
 /**
  * Pulls Cpu time per frequency.
- * Note: this should be pulled for gauge metric only, without condition.
- * The puller keeps internal state of last values. It should not be pulled by
- * different metrics.
- * The pulled data is delta of cpu time from last pull, calculated as
- * following:
- * if current time is larger than last value, take delta between the two.
- * if current time is smaller than last value, there must be a cpu
- * hotplug event, and the current time is taken as delta.
+ * Pulls the time the cpu spend on the frequency index. Frequency index
+ * starts from highest to lowest. The value should be monotonically
+ * increasing since boot. However, if there is a cpu
+ * hotplug event, the value would be reset as well.
  */
 message CpuTimePerFreq {
     optional uint32 cluster = 1;
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 184f69e..554ff8a8 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -181,8 +181,6 @@
 }
 
 void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfig& config) {
-    mkdir(STATS_SERVICE_DIR, S_IRWXU);
-
     // If there is a pre-existing config with same key we should first delete it.
     remove_saved_configs(key);
 
diff --git a/cmds/statsd/src/dimension.cpp b/cmds/statsd/src/dimension.cpp
index 45b3586..09499b6 100644
--- a/cmds/statsd/src/dimension.cpp
+++ b/cmds/statsd/src/dimension.cpp
@@ -19,7 +19,6 @@
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_internal.pb.h"
 #include "dimension.h"
-#include "field_util.h"
 
 
 namespace android {
@@ -220,33 +219,35 @@
 constexpr int UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO = 1;
 constexpr int TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO = 2;
 
-void buildAttributionUidFieldMatcher(const int tagId, const Position position,
-                                     FieldMatcher *matcher) {
-    matcher->set_field(tagId);
-    matcher->add_child()->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
-    FieldMatcher* child = matcher->mutable_child(0)->add_child();
-    child->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
-}
-
-void buildAttributionTagFieldMatcher(const int tagId, const Position position,
-                                     FieldMatcher *matcher) {
-    matcher->set_field(tagId);
-    FieldMatcher* child = matcher->add_child();
+FieldMatcher buildAttributionUidFieldMatcher(const int tagId, const Position position) {
+    FieldMatcher matcher;
+    matcher.set_field(tagId);
+    auto child = matcher.add_child();
     child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
     child->set_position(position);
-    child = child->add_child();
-    child->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    child->add_child()->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    return matcher;
 }
 
-void buildAttributionFieldMatcher(const int tagId, const Position position,
-                                  FieldMatcher *matcher) {
-    matcher->set_field(tagId);
-    FieldMatcher* child = matcher->add_child();
+FieldMatcher buildAttributionTagFieldMatcher(const int tagId, const Position position) {
+    FieldMatcher matcher;
+    matcher.set_field(tagId);
+    FieldMatcher* child = matcher.add_child();
     child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
     child->set_position(position);
-    child = child->add_child();
-    child->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
-    child->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    child->add_child()->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    return matcher;
+}
+
+FieldMatcher buildAttributionFieldMatcher(const int tagId, const Position position) {
+    FieldMatcher matcher;
+    matcher.set_field(tagId);
+    FieldMatcher* child = matcher.add_child();
+    child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
+    child->set_position(position);
+    child->add_child()->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    child->add_child()->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
+    return matcher;
 }
 
 void DimensionsValueToString(const DimensionsValue& value, std::string *flattened) {
diff --git a/cmds/statsd/src/dimension.h b/cmds/statsd/src/dimension.h
index 5bb64a9..d0f96a2 100644
--- a/cmds/statsd/src/dimension.h
+++ b/cmds/statsd/src/dimension.h
@@ -27,12 +27,15 @@
 namespace os {
 namespace statsd {
 
-
 // Returns the leaf node from the DimensionsValue proto. It assume that the input has only one
 // leaf node at most.
 const DimensionsValue* getSingleLeafValue(const DimensionsValue* value);
 DimensionsValue getSingleLeafValue(const DimensionsValue& value);
 
+// Appends the leaf node to the parent tree.
+void appendLeafNodeToParent(const Field& field, const DimensionsValue& value,
+                            DimensionsValue* parentValue);
+
 // Constructs the DimensionsValue protos from the FieldMatcher. Each DimensionsValue proto
 // represents a tree. When the input proto has repeated fields and the input "dimensions" wants
 // "ANY" locations, it will return multiple trees.
diff --git a/cmds/statsd/src/field_util.cpp b/cmds/statsd/src/field_util.cpp
index d10e167..4ff4f74 100644
--- a/cmds/statsd/src/field_util.cpp
+++ b/cmds/statsd/src/field_util.cpp
@@ -184,6 +184,7 @@
     }
 }
 
+namespace {
 void findFields(
        const FieldValueMap& fieldValueMap,
        const FieldMatcher& matcher,
@@ -287,9 +288,18 @@
     }
 }
 
+}  // namespace
+
+void findFields(
+       const FieldValueMap& fieldValueMap,
+       const FieldMatcher& matcher,
+       std::vector<Field>* rootFields) {
+    return findFields(fieldValueMap, matcher, buildSimpleAtomField(matcher.field()), rootFields);
+}
+
 void filterFields(const FieldMatcher& matcher, FieldValueMap* fieldValueMap) {
     std::vector<Field> rootFields;
-    findFields(*fieldValueMap, matcher, buildSimpleAtomField(matcher.field()), &rootFields);
+    findFields(*fieldValueMap, matcher, &rootFields);
     std::set<Field, FieldCmp> rootFieldSet(rootFields.begin(), rootFields.end());
     auto it = fieldValueMap->begin();
     while (it != fieldValueMap->end()) {
@@ -313,6 +323,11 @@
     return true;
 }
 
+bool IsAttributionUidField(const Field& field) {
+    return field.child_size() == 1 && field.child(0).field() == 1
+        && field.child(0).child_size() == 1 && field.child(0).child(0).field() == 1;
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/field_util.h b/cmds/statsd/src/field_util.h
index 3e7d54c..a4dfddd 100644
--- a/cmds/statsd/src/field_util.h
+++ b/cmds/statsd/src/field_util.h
@@ -85,6 +85,9 @@
 // Filter out the fields not in the field matcher.
 void filterFields(const FieldMatcher& matcher, FieldValueMap* fieldValueMap);
 
+// Returns if the field is attribution node uid field.
+bool IsAttributionUidField(const Field& field);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 49a6e33..6782f3f 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -397,6 +397,14 @@
     return dimensionsValue;
 }
 
+DimensionsValue* LogEvent::findFieldValueOrNull(const Field& field) {
+    auto it = mFieldValueMap.find(field);
+    if (it == mFieldValueMap.end()) {
+        return nullptr;
+    }
+    return &it->second;
+}
+
 string LogEvent::ToString() const {
     ostringstream result;
     result << "{ " << mTimestampNs << " (" << mTagId << ")";
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 8f3dedf..fdfa32e 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -132,6 +132,11 @@
         return mFieldValueMap.size();
     }
 
+    /**
+     * Returns the mutable DimensionsValue proto for the specific the field.
+     */
+    DimensionsValue* findFieldValueOrNull(const Field& field);
+
     inline const FieldValueMap& getFieldValueMap() const { return mFieldValueMap; }
 
 private:
diff --git a/cmds/statsd/src/logd/LogListener.h b/cmds/statsd/src/logd/LogListener.h
index 9641226..69ca571 100644
--- a/cmds/statsd/src/logd/LogListener.h
+++ b/cmds/statsd/src/logd/LogListener.h
@@ -33,7 +33,7 @@
     LogListener();
     virtual ~LogListener();
 
-    virtual void OnLogEvent(const LogEvent& msg) = 0;
+    virtual void OnLogEvent(LogEvent* msg) = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/logd/LogReader.cpp b/cmds/statsd/src/logd/LogReader.cpp
index c441a5e..7636268 100644
--- a/cmds/statsd/src/logd/LogReader.cpp
+++ b/cmds/statsd/src/logd/LogReader.cpp
@@ -110,7 +110,7 @@
             LogEvent event(msg);
 
             // Call the listener
-            mListener->OnLogEvent(event);
+            mListener->OnLogEvent(&event);
         }
     }
 
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 46d9b92..48f62e7 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -93,11 +93,6 @@
     return matched;
 }
 
-bool IsAttributionUidField(const Field& field) {
-    return field.child_size() == 1 && field.child(0).field() == 1
-        && field.child(0).child_size() == 1 && field.child(0).child(0).field() == 1;
-}
-
 bool matchesNonRepeatedField(
        const UidMap& uidMap,
        const FieldValueMap& fieldMap,
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 1a4888c..ae47bd8 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -114,6 +114,9 @@
 
 void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
     flushIfNeededLocked(dumpTimeNs);
+    ProtoOutputStream pbOutput;
+    onDumpReportLocked(dumpTimeNs, &pbOutput);
+    parseProtoOutputStream(pbOutput, report);
 }
 
 void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 08b0981..a0239fc 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -141,6 +141,7 @@
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
+    FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 517d21d..b0c3197 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -269,7 +269,7 @@
     }
 }
 
-int UidMap::getParentUidOrSelf(int uid) {
+int UidMap::getHostUidOrSelf(int uid) const {
     lock_guard<mutex> lock(mIsolatedMutex);
 
     auto it = mIsolatedUidMap.find(uid);
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 07e13e0..4e37977 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -90,8 +90,8 @@
     void assignIsolatedUid(int isolatedUid, int parentUid);
     void removeIsolatedUid(int isolatedUid, int parentUid);
 
-    // Returns the parent uid if it exists. Otherwise, returns the same uid that was passed-in.
-    int getParentUidOrSelf(int uid);
+    // Returns the host uid if it exists. Otherwise, returns the same uid that was passed-in.
+    int getHostUidOrSelf(int uid) const;
 
     // Gets the output. If every config key has received the output, then the output is cleared.
     UidMapping getOutput(const ConfigKey& key);
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index 09a43f5..cee9200 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -43,6 +43,19 @@
 // Helper function to write PulledAtomStats to ProtoOutputStream
 void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
                               util::ProtoOutputStream* protoOutput);
+
+template<class T>
+bool parseProtoOutputStream(util::ProtoOutputStream& protoOutput, T* message) {
+    std::string pbBytes;
+    auto iter = protoOutput.data();
+    while (iter.readBuffer() != NULL) {
+        size_t toRead = iter.currentToRead();
+         pbBytes.append(reinterpret_cast<const char*>(iter.readBuffer()), toRead);
+        iter.rp()->move(toRead);
+    }
+    return message->ParseFromArray(pbBytes.c_str(), pbBytes.size());
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/statsd.rc b/cmds/statsd/statsd.rc
index faccd61..c260ae1 100644
--- a/cmds/statsd/statsd.rc
+++ b/cmds/statsd/statsd.rc
@@ -14,3 +14,10 @@
 
 service statsd /system/bin/statsd
     class main
+    user statsd
+    group statsd log
+
+on post-fs-data
+    # Create directory for statsd
+    mkdir /data/misc/stats-data/ 0770 statsd statsd
+    mkdir /data/misc/stats-service/ 0770 statsd statsd
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 945af27..5292f24 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -45,18 +45,18 @@
     addEvent.write(1);    // Indicates creation.
     addEvent.init();
 
-    EXPECT_EQ(101, m->getParentUidOrSelf(101));
+    EXPECT_EQ(101, m->getHostUidOrSelf(101));
 
-    p.OnLogEvent(addEvent);
-    EXPECT_EQ(100, m->getParentUidOrSelf(101));
+    p.OnLogEvent(&addEvent);
+    EXPECT_EQ(100, m->getHostUidOrSelf(101));
 
     LogEvent removeEvent(android::util::ISOLATED_UID_CHANGED, 1);
     removeEvent.write(100);  // parent UID
     removeEvent.write(101);  // isolated UID
     removeEvent.write(0);    // Indicates removal.
     removeEvent.init();
-    p.OnLogEvent(removeEvent);
-    EXPECT_EQ(101, m->getParentUidOrSelf(101));
+    p.OnLogEvent(&removeEvent);
+    EXPECT_EQ(101, m->getHostUidOrSelf(101));
 }
 
 TEST(UidMapTest, TestMatching) {
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index e28dd31..39c9549 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -106,6 +106,10 @@
         {CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
     std::vector<AttributionNode> attributions8 = {CreateAttribution(111, "App1")};
 
+    // GMS core node with isolated uid.
+    const int isolatedUid = 666;
+    std::vector<AttributionNode> attributions9 =
+        {CreateAttribution(isolatedUid, "GMSCoreModule3")};
 
     std::vector<std::unique_ptr<LogEvent>> events;
     // Events 1~4 are in the 1st bucket.
@@ -124,22 +128,30 @@
     events.push_back(CreateAcquireWakelockEvent(
         attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
     events.push_back(CreateAcquireWakelockEvent(
-        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 1));
+        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
     events.push_back(CreateAcquireWakelockEvent(
         attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
+    events.push_back(CreateIsolatedUidChangedEvent(
+        isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
+    events.push_back(CreateIsolatedUidChangedEvent(
+        isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
 
     sortLogEventsByTimestamp(&events);
 
     for (const auto& event : events) {
-        processor->OnLogEvent(*event);
+        processor->OnLogEvent(event.get());
     }
     ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs + 1, &reports);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &reports);
     EXPECT_EQ(reports.reports_size(), 1);
     EXPECT_EQ(reports.reports(0).metrics_size(), 1);
     StatsLogReport::CountMetricDataWrapper countMetrics;
     sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    EXPECT_EQ(countMetrics.data_size(), 3);
+    EXPECT_EQ(countMetrics.data_size(), 4);
 
     auto data = countMetrics.data(0);
     ValidateAttributionUidAndTagDimension(
@@ -165,6 +177,14 @@
 
     data = countMetrics.data(2);
     ValidateAttributionUidAndTagDimension(
+        data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
+
+    data = countMetrics.data(3);
+    ValidateAttributionUidAndTagDimension(
         data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
new file mode 100644
index 0000000..10a6c36
--- /dev/null
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
@@ -0,0 +1,193 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfigForPushedEvent() {
+    StatsdConfig config;
+    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+    auto atomMatcher = CreateSimpleAtomMatcher("", android::util::APP_START_CHANGED);
+    *config.add_atom_matcher() = atomMatcher;
+
+    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+    *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+        CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
+    *config.add_predicate() = isInBackgroundPredicate;
+
+    auto gaugeMetric = config.add_gauge_metric();
+    gaugeMetric->set_id(123456);
+    gaugeMetric->set_what(atomMatcher.id());
+    gaugeMetric->set_condition(isInBackgroundPredicate.id());
+    gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false);
+    auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
+    fieldMatcher->set_field(android::util::APP_START_CHANGED);
+    fieldMatcher->add_child()->set_field(3);  // type (enum)
+    fieldMatcher->add_child()->set_field(4);  // activity_name(str)
+    fieldMatcher->add_child()->set_field(7);  // activity_start_msec(int64)
+    *gaugeMetric->mutable_dimensions() =
+        CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ });
+    gaugeMetric->set_bucket(ONE_MINUTE);
+
+    auto links = gaugeMetric->add_links();
+    links->set_condition(isInBackgroundPredicate.id());
+    auto dimensionWhat = links->mutable_dimensions_in_what();
+    dimensionWhat->set_field(android::util::APP_START_CHANGED);
+    dimensionWhat->add_child()->set_field(1);  // uid field.
+    auto dimensionCondition = links->mutable_dimensions_in_condition();
+    dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+    dimensionCondition->add_child()->set_field(1);  // uid field.
+    return config;
+}
+
+std::unique_ptr<LogEvent> CreateAppStartChangedEvent(
+    const int uid, const string& pkg_name, AppStartChanged::TransitionType type,
+    const string& activity_name, const string& calling_pkg_name, const bool is_instant_app,
+    int64_t activity_start_msec, uint64_t timestampNs) {
+    auto logEvent = std::make_unique<LogEvent>(
+        android::util::APP_START_CHANGED, timestampNs);
+    logEvent->write(uid);
+    logEvent->write(pkg_name);
+    logEvent->write(type);
+    logEvent->write(activity_name);
+    logEvent->write(calling_pkg_name);
+    logEvent->write(is_instant_app);
+    logEvent->write(activity_start_msec);
+    logEvent->init();
+    return logEvent;
+}
+
+}  // namespace
+
+TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
+    auto config = CreateStatsdConfigForPushedEvent();
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    int appUid1 = 123;
+    int appUid2 = 456;
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15));
+    events.push_back(CreateMoveToForegroundEvent(appUid1, bucketStartTimeNs + bucketSizeNs + 250));
+    events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + bucketSizeNs + 350));
+    events.push_back(CreateMoveToForegroundEvent(
+        appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100));
+
+
+    events.push_back(CreateAppStartChangedEvent(
+        appUid1, "app1", AppStartChanged::WARM, "activity_name1", "calling_pkg_name1",
+        true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10));
+    events.push_back(CreateAppStartChangedEvent(
+        appUid1, "app1", AppStartChanged::HOT, "activity_name2", "calling_pkg_name2",
+        true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20));
+    events.push_back(CreateAppStartChangedEvent(
+        appUid1, "app1", AppStartChanged::COLD, "activity_name3", "calling_pkg_name3",
+        true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30));
+    events.push_back(CreateAppStartChangedEvent(
+        appUid1, "app1", AppStartChanged::WARM, "activity_name4", "calling_pkg_name4",
+        true /*is_instant_app*/, 104 /*activity_start_msec*/,
+        bucketStartTimeNs + bucketSizeNs + 30));
+    events.push_back(CreateAppStartChangedEvent(
+        appUid1, "app1", AppStartChanged::COLD, "activity_name5", "calling_pkg_name5",
+        true /*is_instant_app*/, 105 /*activity_start_msec*/,
+        bucketStartTimeNs + 2 * bucketSizeNs));
+    events.push_back(CreateAppStartChangedEvent(
+        appUid1, "app1", AppStartChanged::HOT, "activity_name6", "calling_pkg_name6",
+        false /*is_instant_app*/, 106 /*activity_start_msec*/,
+        bucketStartTimeNs + 2 * bucketSizeNs + 10));
+
+    events.push_back(CreateMoveToBackgroundEvent(appUid2, bucketStartTimeNs + bucketSizeNs + 10));
+    events.push_back(CreateAppStartChangedEvent(
+        appUid2, "app2", AppStartChanged::COLD, "activity_name7", "calling_pkg_name7",
+        true /*is_instant_app*/, 201 /*activity_start_msec*/,
+        bucketStartTimeNs + 2 * bucketSizeNs + 10));
+
+    sortLogEventsByTimestamp(&events);
+
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, &reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+    EXPECT_EQ(gaugeMetrics.data_size(), 2);
+
+    auto data = gaugeMetrics.data(0);
+    EXPECT_EQ(data.dimension().field(), android::util::APP_START_CHANGED);
+    EXPECT_EQ(data.dimension().value_tuple().dimensions_value_size(), 1);
+    EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0).field(), 1 /* uid field */);
+    EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0).value_int(), appUid1);
+    EXPECT_EQ(data.bucket_info_size(), 3);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(0).atom().app_start_changed().type(), AppStartChanged::HOT);
+    EXPECT_EQ(data.bucket_info(0).atom().app_start_changed().activity_name(), "activity_name2");
+    EXPECT_EQ(data.bucket_info(0).atom().app_start_changed().activity_start_msec(), 102L);
+
+    EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(1).atom().app_start_changed().type(), AppStartChanged::WARM);
+    EXPECT_EQ(data.bucket_info(1).atom().app_start_changed().activity_name(), "activity_name4");
+    EXPECT_EQ(data.bucket_info(1).atom().app_start_changed().activity_start_msec(), 104L);
+
+    EXPECT_EQ(data.bucket_info(2).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(2).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(2).atom().app_start_changed().type(), AppStartChanged::COLD);
+    EXPECT_EQ(data.bucket_info(2).atom().app_start_changed().activity_name(), "activity_name5");
+    EXPECT_EQ(data.bucket_info(2).atom().app_start_changed().activity_start_msec(), 105L);
+
+    data = gaugeMetrics.data(1);
+    EXPECT_EQ(data.dimension().field(), android::util::APP_START_CHANGED);
+    EXPECT_EQ(data.dimension().value_tuple().dimensions_value_size(), 1);
+    EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0).field(), 1 /* uid field */);
+    EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0).value_int(), appUid2);
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(0).atom().app_start_changed().type(), AppStartChanged::COLD);
+    EXPECT_EQ(data.bucket_info(0).atom().app_start_changed().activity_name(), "activity_name7");
+    EXPECT_EQ(data.bucket_info(0).atom().app_start_changed().activity_start_msec(), 201L);
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index a81bbb9..cdc4467 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -188,7 +188,7 @@
     sortLogEventsByTimestamp(&events);
 
     for (const auto& event : events) {
-        processor->OnLogEvent(*event);
+        processor->OnLogEvent(event.get());
     }
     ConfigMetricsReportList reports;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports);
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 47e8a72..fcdaafc 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -26,6 +26,8 @@
 
 #ifdef __ANDROID__
 
+namespace {
+
 StatsdConfig CreateStatsdConfig(DurationMetric::AggregationType aggregationType) {
     StatsdConfig config;
     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
@@ -56,6 +58,8 @@
     return config;
 }
 
+}  // namespace
+
 TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions) {
     ConfigKey cfgKey;
     for (auto aggregationType : { DurationMetric::SUM, DurationMetric::MAX_SPARSE }) {
@@ -94,6 +98,7 @@
         auto releaseEvent2 = CreateReleaseWakelockEvent(
             attributions2, "wl2", bucketStartTimeNs + 2 * bucketSizeNs - 15);
 
+
         std::vector<std::unique_ptr<LogEvent>> events;
 
         events.push_back(std::move(screenTurnedOnEvent));
@@ -107,7 +112,7 @@
         sortLogEventsByTimestamp(&events);
 
         for (const auto& event : events) {
-            processor->OnLogEvent(*event);
+            processor->OnLogEvent(event.get());
         }
 
         ConfigMetricsReportList reports;
@@ -119,18 +124,8 @@
 
         auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
         // Validate dimension value.
-        EXPECT_EQ(data.dimension().field(),
-                  android::util::WAKELOCK_STATE_CHANGED);
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value_size(), 1);
-        // Attribution field.
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0).field(), 1);
-        // Uid only.
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0)
-            .value_tuple().dimensions_value_size(), 1);
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0)
-            .value_tuple().dimensions_value(0).field(), 1);
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0)
-            .value_tuple().dimensions_value(0).value_int(), 111);
+        ValidateAttributionUidDimension(
+            data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 111);
         // Validate bucket info.
         EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
         data = reports.reports(0).metrics(0).duration_metrics().data(0);
@@ -147,18 +142,8 @@
         EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
         data = reports.reports(0).metrics(0).duration_metrics().data(0);
         // Validate dimension value.
-        EXPECT_EQ(data.dimension().field(),
-                  android::util::WAKELOCK_STATE_CHANGED);
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value_size(), 1);
-        // Attribution field.
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0).field(), 1);
-        // Uid only.
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0)
-            .value_tuple().dimensions_value_size(), 1);
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0)
-            .value_tuple().dimensions_value(0).field(), 1);
-        EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0)
-            .value_tuple().dimensions_value(0).value_int(), 111);
+        ValidateAttributionUidDimension(
+            data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 111);
         // Two output buckets.
         // The wakelock holding interval in the 1st bucket starts from the screen off event and to
         // the end of the 1st bucket.
@@ -167,6 +152,32 @@
         // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
         // ends at the second screen on event.
         EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
+
+        events.clear();
+        events.push_back(CreateScreenStateChangedEvent(
+            ScreenStateChanged::STATE_OFF, bucketStartTimeNs + 2 * bucketSizeNs + 90));
+        events.push_back(CreateAcquireWakelockEvent(
+            attributions1, "wl3", bucketStartTimeNs + 2 * bucketSizeNs + 100));
+        events.push_back(CreateReleaseWakelockEvent(
+            attributions1, "wl3", bucketStartTimeNs + 5 * bucketSizeNs + 100));
+        sortLogEventsByTimestamp(&events);
+        for (const auto& event : events) {
+            processor->OnLogEvent(event.get());
+        }
+        reports.Clear();
+        processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &reports);
+        EXPECT_EQ(reports.reports_size(), 1);
+        EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+        EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+        EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
+        data = reports.reports(0).metrics(0).duration_metrics().data(0);
+        ValidateAttributionUidDimension(
+            data.dimension(), android::util::WAKELOCK_STATE_CHANGED, 111);
+        // The last wakelock holding spans 4 buckets.
+        EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
+        EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
+        EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
+        EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
     }
 }
 
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index f9ac6d6..718b2e1 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -19,6 +19,14 @@
 namespace os {
 namespace statsd {
 
+AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId) {
+    AtomMatcher atom_matcher;
+    atom_matcher.set_id(StringToId(name));
+    auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+    simple_atom_matcher->set_atom_id(atomId);
+    return atom_matcher;
+}
+
 AtomMatcher CreateWakelockStateChangedAtomMatcher(const string& name,
                                                   WakelockStateChanged::State state) {
     AtomMatcher atom_matcher;
@@ -292,6 +300,17 @@
         uid, ProcessLifeCycleStateChanged::PROCESS_CRASHED, timestampNs);
 }
 
+std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
+    int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) {
+    auto logEvent = std::make_unique<LogEvent>(
+        android::util::ISOLATED_UID_CHANGED, timestampNs);
+    logEvent->write(hostUid);
+    logEvent->write(isolatedUid);
+    logEvent->write(is_create);
+    logEvent->init();
+    return logEvent;
+}
+
 sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
                                               const ConfigKey& key) {
     sp<UidMap> uidMap = new UidMap();
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index f1ce358..7eb93b9 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -23,6 +23,9 @@
 namespace os {
 namespace statsd {
 
+// Create AtomMatcher proto to simply match a specific atom type.
+AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId);
+
 // Create AtomMatcher proto for acquiring wakelock.
 AtomMatcher CreateAcquireWakelockAtomMatcher();
 
@@ -111,6 +114,10 @@
     const std::vector<AttributionNode>& attributions,
     const string& wakelockName, uint64_t timestampNs);
 
+// Create log event for releasing wakelock.
+std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
+    int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs);
+
 // Helper function to create an AttributionNode proto.
 AttributionNode CreateAttribution(const int& uid, const string& tag);
 
diff --git a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
index 857853e..d6f8047 100644
--- a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
+++ b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
@@ -49,7 +49,7 @@
                 android:layout_weight="1"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:maxLength="3"
+                android:maxLength="4"
                 android:text="@integer/replication_default"
                 android:textSize="30dp"/>
         </LinearLayout>
@@ -108,7 +108,7 @@
                 android:layout_weight="1"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:maxLength="2"
+                android:maxLength="4"
                 android:text="@integer/burst_default"
                 android:textSize="30dp"/>
         </LinearLayout>
diff --git a/cmds/statsd/tools/loadtest/run_loadtest.sh b/cmds/statsd/tools/loadtest/run_loadtest.sh
new file mode 100755
index 0000000..3c93a06
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/run_loadtest.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+#
+# Script that measures statsd's PSS under an increasing number of metrics.
+
+# Globals.
+pss=""
+pid=""
+
+# Starts the loadtest.
+start_loadtest() {
+    echo "Starting loadtest"
+    adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "start"
+}
+
+# Stops the loadtest.
+stop_loadtest() {
+    echo "Stopping loadtest"
+    adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "stop"
+}
+
+# Sets the metrics replication.
+# Arguments:
+#   $1: The replication factor.
+set_replication() {
+    adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "set_replication" --ei "replication" "${1}"
+    echo "Replication set to ${1}"
+}
+
+# Reads statsd's pid and PSS.
+update_pid_and_pss() {
+    # Command that reads the PSS for statsd. This also gives us its pid.
+    get_mem=$(adb shell dumpsys meminfo |grep statsd)
+    # Looks for statsd's pid.
+    regex="([0-9,]+)K: statsd \(pid ([0-9]+)\).*"
+    if [[ $get_mem =~ $regex ]]; then
+        pss=$(echo "${BASH_REMATCH[1]}" | tr -d , | sed 's/\.//g')
+        pid=$(echo "${BASH_REMATCH[2]}")
+    else
+        echo $cmd doesnt match $regex
+    fi
+}
+
+# Kills statsd.
+# Assumes the pid has been set.
+kill_statsd() {
+    echo "Killing statsd (pid ${pid})"
+    adb shell kill -9 "${pid}"
+}
+
+# Main loop.
+main() {
+    start_time=$(date +%s)
+    values=()
+    stop_loadtest
+
+    echo ""
+    echo "********************* NEW LOADTEST ************************"
+    update_pid_and_pss
+    for replication in 1 2 4 8 16 32 64 128 256 512 1024 2048 4096
+    do
+        echo "**** Starting test at replication ${replication} ****"
+
+        # (1) Restart statsd. This will ensure its state is empty.
+        kill_statsd
+        sleep 3 # wait a bit for it to restart
+        update_pid_and_pss
+        echo "Before the test, statsd's PSS is ${pss}"
+
+        # (2) Set the replication.
+        set_replication "${replication}"
+        sleep 1 # wait a bit
+
+        # (3) Start the loadtest.
+        start_loadtest
+
+        # (4) Wait several seconds, then read the PSS.
+        sleep 100 && update_pid_and_pss
+        echo "During the test, statsd's PSS is ${pss}"
+        values+=(${pss})
+
+        echo "Values: ${values[@]}"
+
+        # (5) Stop loadtest.
+        stop_loadtest
+        sleep 2
+
+        echo ""
+    done
+
+    end_time=$(date +%s)
+    echo "Completed loadtest in $((${end_time} - ${start_time})) seconds."
+
+    values_as_str=$(IFS=$'\n'; echo "${values[*]}")
+    echo "The PSS values are:"
+    echo "${values_as_str}"
+    echo ""
+}
+
+main
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
index 19087d8..862ebe14 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
@@ -22,18 +22,28 @@
 import java.util.List;
 
 public class DisplayProtoUtils {
+    private static final int MAX_NUM_METRICS_TO_DISPLAY = 10;
+
     public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
-        sb.append("ConfigKey: ");
+        sb.append("******************** Report ********************\n");
         if (reports.hasConfigKey()) {
+            sb.append("ConfigKey: ");
             com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
             sb.append("\tuid: ").append(key.getUid()).append(" id: ").append(key.getId())
                     .append("\n");
         }
 
+        int numMetrics = 0;
         for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
             sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
             for (StatsLog.StatsLogReport log : report.getMetricsList()) {
-                sb.append("\n\n");
+                numMetrics++;
+                if (numMetrics > MAX_NUM_METRICS_TO_DISPLAY) {
+                    sb.append("... output truncated\n");
+                    sb.append("************************************************");
+                    return;
+                }
+                sb.append("\n");
                 sb.append("metric id: ").append(log.getMetricId()).append("\n");
                 sb.append("start time:").append(getDateStr(log.getStartReportNanos())).append("\n");
                 sb.append("end time:").append(getDateStr(log.getEndReportNanos())).append("\n");
@@ -65,6 +75,7 @@
                 }
             }
         }
+        sb.append("************************************************");
     }
 
     public static String getDateStr(long nanoSec) {
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
index c81ac07..26c1c72 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
@@ -76,10 +76,12 @@
  */
 public class LoadtestActivity extends Activity implements AdapterView.OnItemSelectedListener {
 
-    private static final String TAG = "StatsdLoadtest";
+    private static final String TAG = "loadtest.LoadtestActivity";
     public static final String TYPE = "type";
     private static final String PUSH_ALARM = "push_alarm";
     public static final String PERF_ALARM = "perf_alarm";
+    private static final String SET_REPLICATION = "set_replication";
+    private static final String REPLICATION = "replication";
     private static final String START = "start";
     private static final String STOP = "stop";
     private static final Map<String, TimeUnit> TIME_UNIT_MAP = initializeTimeUnitMap();
@@ -231,7 +233,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        Log.d(TAG, "Starting loadtest");
+        Log.d(TAG, "Starting loadtest Activity");
 
         setContentView(R.layout.activity_loadtest);
         mReportText = (TextView) findViewById(R.id.report_text);
@@ -289,6 +291,11 @@
             case PUSH_ALARM:
                 onAlarm();
                 break;
+            case SET_REPLICATION:
+                if (intent.hasExtra(REPLICATION)) {
+                    setReplication(intent.getIntExtra(REPLICATION, 0));
+                }
+                break;
             case START:
                 startLoadtest();
                 break;
@@ -340,6 +347,10 @@
                 ConfigMetricsReportList reports = null;
                 try {
                     reports = ConfigMetricsReportList.parseFrom(data);
+                    Log.d(TAG, "Num reports: " + reports.getReportsCount());
+                    StringBuilder sb = new StringBuilder();
+                    DisplayProtoUtils.displayLogReport(sb, reports);
+                    Log.d(TAG, sb.toString());
                 } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                     Log.d(TAG, "Invalid data");
                 }
@@ -411,9 +422,6 @@
         // Prepare to push a sequence of atoms to logd.
         mPusher = new SequencePusher(mBurst, mPlacebo);
 
-        // Force a data flush by requesting data.
-        getData();
-
         // Create a config and push it to statsd.
         if (!setConfig(mFactory.getConfig(mReplication, mBucket, mPlacebo,
                 mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric,
@@ -464,6 +472,9 @@
             mPerfData = null;
         }
 
+        // Obtain the latest data and display it.
+        getData();
+
         long elapsedTimeMins = (long) Math.floor(
             (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
         mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
@@ -541,7 +552,10 @@
     }
 
     private synchronized void setReplication(int replication) {
-        mReplication = replication;
+        if (mStarted) {
+          return;
+        }
+        mReplicationText.setText("" + replication);
     }
 
     private synchronized void setPeriodSecs(long periodSecs) {
@@ -573,7 +587,7 @@
     private void initBurst() {
         mBurst = getResources().getInteger(R.integer.burst_default);
         mBurstText = (EditText) findViewById(R.id.burst);
-        mBurstText.addTextChangedListener(new NumericalWatcher(mBurstText, 0, 50) {
+        mBurstText.addTextChangedListener(new NumericalWatcher(mBurstText, 0, 1000) {
             @Override
             public void onNewValue(int newValue) {
                 setBurst(newValue);
@@ -585,10 +599,10 @@
     private void initReplication() {
         mReplication = getResources().getInteger(R.integer.replication_default);
         mReplicationText = (EditText) findViewById(R.id.replication);
-        mReplicationText.addTextChangedListener(new NumericalWatcher(mReplicationText, 1, 100) {
+        mReplicationText.addTextChangedListener(new NumericalWatcher(mReplicationText, 1, 4096) {
             @Override
             public void onNewValue(int newValue) {
-                setReplication(newValue);
+                mReplication = newValue;
             }
         });
         handleFocus(mReplicationText);
@@ -606,9 +620,7 @@
         mBucketSpinner.setOnItemSelectedListener(this);
 
         for (String label : TIME_UNIT_MAP.keySet()) {
-          Log.d(TAG, "EVALUATE " + label + " VS " + defaultValue);
           if (defaultValue.equals(TIME_UNIT_MAP.get(label).toString())) {
-                Log.d(TAG, " FOUND IT");
                 mBucketSpinner.setSelection(dataAdapter.getPosition(label));
             }
         }
diff --git a/core/java/Android.bp b/core/java/Android.bp
index b43cf27..afa08e6 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -3,6 +3,11 @@
     srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"],
 }
 
+filegroup {
+    name: "IDropBoxManagerService.aidl",
+    srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"],
+}
+
 // only used by key_store_service
 cc_library_shared {
     name: "libkeystore_aidl",
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 847f91b..4554584 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -485,11 +485,11 @@
      * all activities that are visible to the user. */
     public static final int PROCESS_STATE_TOP = 2;
 
-    /** @hide Process is hosting a foreground service due to a system binding. */
-    public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;
-
     /** @hide Process is hosting a foreground service. */
-    public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
+    public static final int PROCESS_STATE_FOREGROUND_SERVICE = 3;
+
+    /** @hide Process is hosting a foreground service due to a system binding. */
+    public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 4;
 
     /** @hide Process is important to the user, and something they are aware of. */
     public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 5;
@@ -3086,11 +3086,11 @@
             } else if (importance >= IMPORTANCE_VISIBLE) {
                 return PROCESS_STATE_IMPORTANT_FOREGROUND;
             } else if (importance >= IMPORTANCE_TOP_SLEEPING_PRE_28) {
-                return PROCESS_STATE_FOREGROUND_SERVICE;
+                return PROCESS_STATE_IMPORTANT_FOREGROUND;
             } else if (importance >= IMPORTANCE_FOREGROUND_SERVICE) {
                 return PROCESS_STATE_FOREGROUND_SERVICE;
             } else {
-                return PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                return PROCESS_STATE_TOP;
             }
         }
 
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 60a5a11..972ffcb 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -319,4 +319,9 @@
     }
 
     public abstract void registerScreenObserver(ScreenObserver observer);
+
+    /**
+     * Returns if more users can be started without stopping currently running users.
+     */
+    public abstract boolean canStartMoreUsers();
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index de346f3..70c383b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1752,9 +1752,11 @@
                     handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
                             (IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
                     break;
-                case ATTACH_AGENT:
-                    handleAttachAgent((String) msg.obj);
+                case ATTACH_AGENT: {
+                    Application app = getApplication();
+                    handleAttachAgent((String) msg.obj, app != null ? app.mLoadedApk : null);
                     break;
+                }
                 case APPLICATION_INFO_CHANGED:
                     mUpdatingSystemConfig = true;
                     try {
@@ -1768,7 +1770,14 @@
                             (String[]) ((SomeArgs) msg.obj).arg2);
                     break;
                 case EXECUTE_TRANSACTION:
-                    mTransactionExecutor.execute(((ClientTransaction) msg.obj));
+                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
+                    mTransactionExecutor.execute(transaction);
+                    if (isSystem()) {
+                        // Client transactions inside system process are recycled on the client side
+                        // instead of ClientLifecycleManager to avoid being cleared before this
+                        // message is handled.
+                        transaction.recycle();
+                    }
                     break;
             }
             Object obj = msg.obj;
@@ -3239,11 +3248,23 @@
         }
     }
 
-    static final void handleAttachAgent(String agent) {
+    private static boolean attemptAttachAgent(String agent, ClassLoader classLoader) {
         try {
-            VMDebug.attachAgent(agent);
+            VMDebug.attachAgent(agent, classLoader);
+            return true;
         } catch (IOException e) {
-            Slog.e(TAG, "Attaching agent failed: " + agent);
+            Slog.e(TAG, "Attaching agent with " + classLoader + " failed: " + agent);
+            return false;
+        }
+    }
+
+    static void handleAttachAgent(String agent, LoadedApk loadedApk) {
+        ClassLoader classLoader = loadedApk != null ? loadedApk.getClassLoader() : null;
+        if (attemptAttachAgent(agent, classLoader)) {
+            return;
+        }
+        if (classLoader != null) {
+            attemptAttachAgent(agent, null);
         }
     }
 
@@ -5535,12 +5556,16 @@
         mCompatConfiguration = new Configuration(data.config);
 
         mProfiler = new Profiler();
+        String agent = null;
         if (data.initProfilerInfo != null) {
             mProfiler.profileFile = data.initProfilerInfo.profileFile;
             mProfiler.profileFd = data.initProfilerInfo.profileFd;
             mProfiler.samplingInterval = data.initProfilerInfo.samplingInterval;
             mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler;
             mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput;
+            if (data.initProfilerInfo.attachAgentDuringBind) {
+                agent = data.initProfilerInfo.agent;
+            }
         }
 
         // send up app name; do this *before* waiting for debugger
@@ -5590,6 +5615,10 @@
 
         data.loadedApk = getLoadedApkNoCheck(data.appInfo, data.compatInfo);
 
+        if (agent != null) {
+            handleAttachAgent(agent, data.loadedApk);
+        }
+
         /**
          * Switch this process to density compatibility mode if needed.
          */
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 82f2bac..4048e65 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2738,6 +2738,24 @@
     }
 
     @Override
+    public CharSequence getHarmfulAppWarning(String packageName) {
+        try {
+            return mPM.getHarmfulAppWarning(packageName, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void setHarmfulAppWarning(String packageName, CharSequence warning) {
+        try {
+            mPM.setHarmfulAppWarning(packageName, warning, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
     public ArtManager getArtManager() {
         synchronized (mLock) {
             if (mArtManager == null) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index a9e633f..696899f 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -620,8 +620,9 @@
     boolean updateDisplayOverrideConfiguration(in Configuration values, int displayId);
     void moveStackToDisplay(int stackId, int displayId);
     boolean requestAutofillData(in IAssistDataReceiver receiver, in Bundle receiverExtras,
-                                in IBinder activityToken, int flags);
-    void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
+            in IBinder activityToken, int flags);
+    void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback,
+            in CharSequence message);
     int restartUserInBackground(int userId);
 
     /** Cancels the window transitions for the given task. */
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index d0f84c8..024dbcb 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.trust.ITrustManager;
 import android.content.Context;
@@ -172,6 +173,7 @@
      *
      * @hide
      */
+    @SystemApi
     public Intent createConfirmFactoryResetCredentialIntent(
             CharSequence title, CharSequence description, CharSequence alternateButtonLabel) {
         if (!LockPatternUtils.frpCredentialEnabled(mContext)) {
@@ -475,6 +477,39 @@
      */
     public void requestDismissKeyguard(@NonNull Activity activity,
             @Nullable KeyguardDismissCallback callback) {
+        requestDismissKeyguard(activity, null /* message */, callback);
+    }
+
+    /**
+     * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
+     * be dismissed.
+     * <p>
+     * If the Keyguard is not secure or the device is currently in a trusted state, calling this
+     * method will immediately dismiss the Keyguard without any user interaction.
+     * <p>
+     * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
+     * UI so the user can enter their credentials.
+     * <p>
+     * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true,
+     * the screen will turn on when the keyguard is dismissed.
+     *
+     * @param activity The activity requesting the dismissal. The activity must be either visible
+     *                 by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
+     *                 which it would be visible if Keyguard would not be hiding it. If that's not
+     *                 the case, the request will fail immediately and
+     *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
+     * @param message  A message that will be shown in the keyguard explaining why the user
+     *                 would want to dismiss it.
+     * @param callback The callback to be called if the request to dismiss Keyguard was successful
+     *                 or {@code null} if the caller isn't interested in knowing the result. The
+     *                 callback will not be invoked if the activity was destroyed before the
+     *                 callback was received.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SHOW_KEYGUARD_MESSAGE)
+    @SystemApi
+    public void requestDismissKeyguard(@NonNull Activity activity, @Nullable CharSequence message,
+            @Nullable KeyguardDismissCallback callback) {
         try {
             mAm.dismissKeyguard(activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
                 @Override
@@ -497,9 +532,9 @@
                         activity.mHandler.post(callback::onDismissCancelled);
                     }
                 }
-            });
+            }, message);
         } catch (RemoteException e) {
-            Log.i(TAG, "Failed to dismiss keyguard: " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 046a128..75dc571 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1022,10 +1022,18 @@
     /**
      * {@link #extras} key: A String array containing the people that this notification relates to,
      * each of which was supplied to {@link Builder#addPerson(String)}.
+     *
+     * @deprecated the actual objects are now in {@link #EXTRA_PEOPLE_LIST}
      */
     public static final String EXTRA_PEOPLE = "android.people";
 
     /**
+     * {@link #extras} key: An arrayList of {@link Person} objects containing the people that
+     * this notification relates to.
+     */
+    public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+
+    /**
      * Allow certain system-generated notifications to appear before the device is provisioned.
      * Only available to notifications coming from the android package.
      * @hide
@@ -1063,10 +1071,20 @@
      * direct replies
      * {@link android.app.Notification.MessagingStyle} notification. This extra is a
      * {@link CharSequence}
+     *
+     * @deprecated use {@link #EXTRA_MESSAGING_PERSON}
      */
     public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
 
     /**
+     * {@link #extras} key: the person to be displayed for all messages sent by the user including
+     * direct replies
+     * {@link android.app.Notification.MessagingStyle} notification. This extra is a
+     * {@link Person}
+     */
+    public static final String EXTRA_MESSAGING_PERSON = "android.messagingUser";
+
+    /**
      * {@link #extras} key: a {@link CharSequence} to be displayed as the title to a conversation
      * represented by a {@link android.app.Notification.MessagingStyle}
      */
@@ -1250,10 +1268,67 @@
          */
         private static final String EXTRA_DATA_ONLY_INPUTS = "android.extra.DATA_ONLY_INPUTS";
 
+        /**
+         * {@link }: No semantic action defined.
+         */
+        public static final int SEMANTIC_ACTION_NONE = 0;
+
+        /**
+         * {@code SemanticAction}: Reply to a conversation, chat, group, or wherever replies
+         * may be appropriate.
+         */
+        public static final int SEMANTIC_ACTION_REPLY = 1;
+
+        /**
+         * {@code SemanticAction}: Mark content as read.
+         */
+        public static final int SEMANTIC_ACTION_MARK_AS_READ = 2;
+
+        /**
+         * {@code SemanticAction}: Mark content as unread.
+         */
+        public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3;
+
+        /**
+         * {@code SemanticAction}: Delete the content associated with the notification. This
+         * could mean deleting an email, message, etc.
+         */
+        public static final int SEMANTIC_ACTION_DELETE = 4;
+
+        /**
+         * {@code SemanticAction}: Archive the content associated with the notification. This
+         * could mean archiving an email, message, etc.
+         */
+        public static final int SEMANTIC_ACTION_ARCHIVE = 5;
+
+        /**
+         * {@code SemanticAction}: Mute the content associated with the notification. This could
+         * mean silencing a conversation or currently playing media.
+         */
+        public static final int SEMANTIC_ACTION_MUTE = 6;
+
+        /**
+         * {@code SemanticAction}: Unmute the content associated with the notification. This could
+         * mean un-silencing a conversation or currently playing media.
+         */
+        public static final int SEMANTIC_ACTION_UNMUTE = 7;
+
+        /**
+         * {@code SemanticAction}: Mark content with a thumbs up.
+         */
+        public static final int SEMANTIC_ACTION_THUMBS_UP = 8;
+
+        /**
+         * {@code SemanticAction}: Mark content with a thumbs down.
+         */
+        public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9;
+
+
         private final Bundle mExtras;
         private Icon mIcon;
         private final RemoteInput[] mRemoteInputs;
         private boolean mAllowGeneratedReplies = true;
+        private final @SemanticAction int mSemanticAction;
 
         /**
          * Small icon representing the action.
@@ -1288,6 +1363,7 @@
             mExtras = Bundle.setDefusable(in.readBundle(), true);
             mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR);
             mAllowGeneratedReplies = in.readInt() == 1;
+            mSemanticAction = in.readInt();
         }
 
         /**
@@ -1295,12 +1371,14 @@
          */
         @Deprecated
         public Action(int icon, CharSequence title, PendingIntent intent) {
-            this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true);
+            this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true,
+                    SEMANTIC_ACTION_NONE);
         }
 
         /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */
         private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
-                RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
+                RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
+                       @SemanticAction int semanticAction) {
             this.mIcon = icon;
             if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
                 this.icon = icon.getResId();
@@ -1310,6 +1388,7 @@
             this.mExtras = extras != null ? extras : new Bundle();
             this.mRemoteInputs = remoteInputs;
             this.mAllowGeneratedReplies = allowGeneratedReplies;
+            this.mSemanticAction = semanticAction;
         }
 
         /**
@@ -1348,6 +1427,15 @@
         }
 
         /**
+         * Returns the {@code SemanticAction} associated with this {@link Action}. A
+         * {@code SemanticAction} denotes what an {@link Action}'s {@link PendingIntent} will do
+         * (eg. reply, mark as read, delete, etc).
+         */
+        public @SemanticAction int getSemanticAction() {
+            return mSemanticAction;
+        }
+
+        /**
          * Get the list of inputs to be collected from the user that ONLY accept data when this
          * action is sent. These remote inputs are guaranteed to return true on a call to
          * {@link RemoteInput#isDataOnly}.
@@ -1371,6 +1459,7 @@
             private boolean mAllowGeneratedReplies = true;
             private final Bundle mExtras;
             private ArrayList<RemoteInput> mRemoteInputs;
+            private @SemanticAction int mSemanticAction;
 
             /**
              * Construct a new builder for {@link Action} object.
@@ -1390,7 +1479,7 @@
              * @param intent the {@link PendingIntent} to fire when users trigger this action
              */
             public Builder(Icon icon, CharSequence title, PendingIntent intent) {
-                this(icon, title, intent, new Bundle(), null, true);
+                this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE);
             }
 
             /**
@@ -1401,11 +1490,12 @@
             public Builder(Action action) {
                 this(action.getIcon(), action.title, action.actionIntent,
                         new Bundle(action.mExtras), action.getRemoteInputs(),
-                        action.getAllowGeneratedReplies());
+                        action.getAllowGeneratedReplies(), action.getSemanticAction());
             }
 
             private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
-                    RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
+                    RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
+                            @SemanticAction int semanticAction) {
                 mIcon = icon;
                 mTitle = title;
                 mIntent = intent;
@@ -1415,6 +1505,7 @@
                     Collections.addAll(mRemoteInputs, remoteInputs);
                 }
                 mAllowGeneratedReplies = allowGeneratedReplies;
+                mSemanticAction = semanticAction;
             }
 
             /**
@@ -1470,6 +1561,19 @@
             }
 
             /**
+             * Sets the {@code SemanticAction} for this {@link Action}. A
+             * {@code SemanticAction} denotes what an {@link Action}'s
+             * {@link PendingIntent} will do (eg. reply, mark as read, delete, etc).
+             * @param semanticAction a SemanticAction defined within {@link Action} with
+             * {@code SEMANTIC_ACTION_} prefixes
+             * @return this object for method chaining
+             */
+            public Builder setSemanticAction(@SemanticAction int semanticAction) {
+                mSemanticAction = semanticAction;
+                return this;
+            }
+
+            /**
              * Apply an extender to this action builder. Extenders may be used to add
              * metadata or change options on this builder.
              */
@@ -1510,7 +1614,7 @@
                 RemoteInput[] textInputsArr = textInputs.isEmpty()
                         ? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
                 return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
-                        mAllowGeneratedReplies);
+                        mAllowGeneratedReplies, mSemanticAction);
             }
         }
 
@@ -1522,12 +1626,15 @@
                     actionIntent, // safe to alias
                     mExtras == null ? new Bundle() : new Bundle(mExtras),
                     getRemoteInputs(),
-                    getAllowGeneratedReplies());
+                    getAllowGeneratedReplies(),
+                    getSemanticAction());
         }
+
         @Override
         public int describeContents() {
             return 0;
         }
+
         @Override
         public void writeToParcel(Parcel out, int flags) {
             final Icon ic = getIcon();
@@ -1547,7 +1654,9 @@
             out.writeBundle(mExtras);
             out.writeTypedArray(mRemoteInputs, flags);
             out.writeInt(mAllowGeneratedReplies ? 1 : 0);
+            out.writeInt(mSemanticAction);
         }
+
         public static final Parcelable.Creator<Action> CREATOR =
                 new Parcelable.Creator<Action>() {
             public Action createFromParcel(Parcel in) {
@@ -1809,6 +1918,29 @@
                 return (mFlags & FLAG_HINT_DISPLAY_INLINE) != 0;
             }
         }
+
+        /**
+         * Provides meaning to an {@link Action} that hints at what the associated
+         * {@link PendingIntent} will do. For example, an {@link Action} with a
+         * {@link PendingIntent} that replies to a text message notification may have the
+         * {@link #SEMANTIC_ACTION_REPLY} {@code SemanticAction} set within it.
+         *
+         * @hide
+         */
+        @IntDef(prefix = { "SEMANTIC_ACTION_" }, value = {
+                SEMANTIC_ACTION_NONE,
+                SEMANTIC_ACTION_REPLY,
+                SEMANTIC_ACTION_MARK_AS_READ,
+                SEMANTIC_ACTION_MARK_AS_UNREAD,
+                SEMANTIC_ACTION_DELETE,
+                SEMANTIC_ACTION_ARCHIVE,
+                SEMANTIC_ACTION_MUTE,
+                SEMANTIC_ACTION_UNMUTE,
+                SEMANTIC_ACTION_THUMBS_UP,
+                SEMANTIC_ACTION_THUMBS_DOWN
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface SemanticAction {}
     }
 
     /**
@@ -2819,7 +2951,7 @@
         private Bundle mUserExtras = new Bundle();
         private Style mStyle;
         private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
-        private ArrayList<String> mPersonList = new ArrayList<String>();
+        private ArrayList<Person> mPersonList = new ArrayList<>();
         private NotificationColorUtil mColorUtil;
         private boolean mIsLegacy;
         private boolean mIsLegacyInitialized;
@@ -2910,8 +3042,9 @@
                     Collections.addAll(mActions, mN.actions);
                 }
 
-                if (mN.extras.containsKey(EXTRA_PEOPLE)) {
-                    Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE));
+                if (mN.extras.containsKey(EXTRA_PEOPLE_LIST)) {
+                    ArrayList<Person> people = mN.extras.getParcelableArrayList(EXTRA_PEOPLE_LIST);
+                    mPersonList.addAll(people);
                 }
 
                 if (mN.getSmallIcon() == null && mN.icon != 0) {
@@ -3621,13 +3754,41 @@
          * URIs.  The path part of these URIs must exist in the contacts database, in the
          * appropriate column, or the reference will be discarded as invalid. Telephone schema
          * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}.
+         * It is also possible to provide a URI with the schema {@code name:} in order to uniquely
+         * identify a person without an entry in the contacts database.
          * </P>
          *
          * @param uri A URI for the person.
          * @see Notification#EXTRA_PEOPLE
+         * @deprecated use {@link #addPerson(Person)}
          */
         public Builder addPerson(String uri) {
-            mPersonList.add(uri);
+            addPerson(new Person().setUri(uri));
+            return this;
+        }
+
+        /**
+         * Add a person that is relevant to this notification.
+         *
+         * <P>
+         * Depending on user preferences, this annotation may allow the notification to pass
+         * through interruption filters, if this notification is of category {@link #CATEGORY_CALL}
+         * or {@link #CATEGORY_MESSAGE}. The addition of people may also cause this notification to
+         * appear more prominently in the user interface.
+         * </P>
+         *
+         * <P>
+         * A person should usually contain a uri in order to benefit from the ranking boost.
+         * However, even if no uri is provided, it's beneficial to provide other people in the
+         * notification, such that listeners and voice only devices can announce and handle them
+         * properly.
+         * </P>
+         *
+         * @param person the person to add.
+         * @see Notification#EXTRA_PEOPLE_LIST
+         */
+        public Builder addPerson(Person person) {
+            mPersonList.add(person);
             return this;
         }
 
@@ -3934,7 +4095,10 @@
             contentView.setViewVisibility(R.id.chronometer, View.GONE);
             contentView.setViewVisibility(R.id.header_text, View.GONE);
             contentView.setTextViewText(R.id.header_text, null);
+            contentView.setViewVisibility(R.id.header_text_secondary, View.GONE);
+            contentView.setTextViewText(R.id.header_text_secondary, null);
             contentView.setViewVisibility(R.id.header_text_divider, View.GONE);
+            contentView.setViewVisibility(R.id.header_text_secondary_divider, View.GONE);
             contentView.setViewVisibility(R.id.time_divider, View.GONE);
             contentView.setViewVisibility(R.id.time, View.GONE);
             contentView.setImageViewIcon(R.id.profile_badge, null);
@@ -3965,7 +4129,7 @@
 
             final Bundle ex = mN.extras;
             updateBackgroundColor(contentView);
-            bindNotificationHeader(contentView, p.ambient);
+            bindNotificationHeader(contentView, p.ambient, p.headerTextSecondary);
             bindLargeIcon(contentView, p.hideLargeIcon, p.alwaysShowReply);
             boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex);
             if (p.title != null) {
@@ -4248,12 +4412,14 @@
             return null;
         }
 
-        private void bindNotificationHeader(RemoteViews contentView, boolean ambient) {
+        private void bindNotificationHeader(RemoteViews contentView, boolean ambient,
+                CharSequence secondaryHeaderText) {
             bindSmallIcon(contentView, ambient);
             bindHeaderAppName(contentView, ambient);
             if (!ambient) {
                 // Ambient view does not have these
                 bindHeaderText(contentView);
+                bindHeaderTextSecondary(contentView, secondaryHeaderText);
                 bindHeaderChronometerAndTime(contentView);
                 bindProfileBadge(contentView);
             }
@@ -4322,6 +4488,17 @@
             }
         }
 
+        private void bindHeaderTextSecondary(RemoteViews contentView, CharSequence secondaryText) {
+            if (!TextUtils.isEmpty(secondaryText)) {
+                contentView.setTextViewText(R.id.header_text_secondary, processTextSpans(
+                        processLegacyText(secondaryText)));
+                setTextViewColorSecondary(contentView, R.id.header_text_secondary);
+                contentView.setViewVisibility(R.id.header_text_secondary, View.VISIBLE);
+                contentView.setViewVisibility(R.id.header_text_secondary_divider, View.VISIBLE);
+                setTextViewColorSecondary(contentView, R.id.header_text_secondary_divider);
+            }
+        }
+
         /**
          * @hide
          */
@@ -4555,7 +4732,7 @@
                     ambient ? R.layout.notification_template_ambient_header
                             : R.layout.notification_template_header);
             resetNotificationHeader(header);
-            bindNotificationHeader(header, ambient);
+            bindNotificationHeader(header, ambient, null);
             if (colorized != null) {
                 mN.extras.putBoolean(EXTRA_COLORIZED, colorized);
             } else {
@@ -4968,8 +5145,7 @@
                 mActions.toArray(mN.actions);
             }
             if (!mPersonList.isEmpty()) {
-                mN.extras.putStringArray(EXTRA_PEOPLE,
-                        mPersonList.toArray(new String[mPersonList.size()]));
+                mN.extras.putParcelableArrayList(EXTRA_PEOPLE_LIST, mPersonList);
             }
             if (mN.bigContentView != null || mN.contentView != null
                     || mN.headsUpContentView != null) {
@@ -5965,7 +6141,7 @@
          */
         public static final int MAXIMUM_RETAINED_MESSAGES = 25;
 
-        CharSequence mUserDisplayName;
+        @NonNull Person mUser;
         @Nullable CharSequence mConversationTitle;
         List<Message> mMessages = new ArrayList<>();
         List<Message> mHistoricMessages = new ArrayList<>();
@@ -5979,16 +6155,40 @@
          * user before the posting app reposts the notification with those messages after they've
          * been actually sent and in previous messages sent by the user added in
          * {@link #addMessage(Notification.MessagingStyle.Message)}
+         *
+         * @deprecated use {@code MessagingStyle(Person)}
          */
         public MessagingStyle(@NonNull CharSequence userDisplayName) {
-            mUserDisplayName = userDisplayName;
+            this(new Person().setName(userDisplayName));
+        }
+
+        /**
+         * @param user Required - The person displayed for any messages that are sent by the
+         * user. Any messages added with {@link #addMessage(Notification.MessagingStyle.Message)}
+         * who don't have a Person associated with it will be displayed as if they were sent
+         * by this user. The user also needs to have a valid name associated with it.
+         */
+        public MessagingStyle(@NonNull Person user) {
+            mUser = user;
+            if (user == null || user.getName() == null) {
+                throw new RuntimeException("user must be valid and have a name");
+            }
+        }
+
+        /**
+         * @return the user to be displayed for any replies sent by the user
+         */
+        public Person getUser() {
+            return mUser;
         }
 
         /**
          * Returns the name to be displayed for any replies sent by the user
+         *
+         * @deprecated use {@link #getUser()} instead
          */
         public CharSequence getUserDisplayName() {
-            return mUserDisplayName;
+            return mUser.getName();
         }
 
         /**
@@ -6031,8 +6231,28 @@
          * @see Message#Message(CharSequence, long, CharSequence)
          *
          * @return this object for method chaining
+         *
+         * @deprecated use {@link #addMessage(CharSequence, long, Person)}
          */
         public MessagingStyle addMessage(CharSequence text, long timestamp, CharSequence sender) {
+            return addMessage(text, timestamp,
+                    sender == null ? null : new Person().setName(sender));
+        }
+
+        /**
+         * Adds a message for display by this notification. Convenience call for a simple
+         * {@link Message} in {@link #addMessage(Notification.MessagingStyle.Message)}.
+         * @param text A {@link CharSequence} to be displayed as the message content
+         * @param timestamp Time at which the message arrived
+         * @param sender The {@link Person} who sent the message.
+         * Should be <code>null</code> for messages by the current user, in which case
+         * the platform will insert the user set in {@code MessagingStyle(Person)}.
+         *
+         * @see Message#Message(CharSequence, long, CharSequence)
+         *
+         * @return this object for method chaining
+         */
+        public MessagingStyle addMessage(CharSequence text, long timestamp, Person sender) {
             return addMessage(new Message(text, timestamp, sender));
         }
 
@@ -6131,8 +6351,10 @@
         @Override
         public void addExtras(Bundle extras) {
             super.addExtras(extras);
-            if (mUserDisplayName != null) {
-                extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUserDisplayName);
+            if (mUser != null) {
+                // For legacy usages
+                extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUser.getName());
+                extras.putParcelable(EXTRA_MESSAGING_PERSON, mUser);
             }
             if (mConversationTitle != null) {
                 extras.putCharSequence(EXTRA_CONVERSATION_TITLE, mConversationTitle);
@@ -6152,14 +6374,15 @@
             Message m = findLatestIncomingMessage();
             CharSequence text = (m == null) ? null : m.mText;
             CharSequence sender = m == null ? null
-                    : TextUtils.isEmpty(m.mSender) ? mUserDisplayName : m.mSender;
+                    : m.mSender == null || TextUtils.isEmpty(m.mSender.getName())
+                            ? mUser.getName() : m.mSender.getName();
             CharSequence title;
             if (!TextUtils.isEmpty(mConversationTitle)) {
                 if (!TextUtils.isEmpty(sender)) {
                     BidiFormatter bidi = BidiFormatter.getInstance();
                     title = mBuilder.mContext.getString(
                             com.android.internal.R.string.notification_messaging_title_template,
-                            bidi.unicodeWrap(mConversationTitle), bidi.unicodeWrap(m.mSender));
+                            bidi.unicodeWrap(mConversationTitle), bidi.unicodeWrap(sender));
                 } else {
                     title = mConversationTitle;
                 }
@@ -6182,7 +6405,11 @@
         protected void restoreFromExtras(Bundle extras) {
             super.restoreFromExtras(extras);
 
-            mUserDisplayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME);
+            mUser = extras.getParcelable(EXTRA_MESSAGING_PERSON);
+            if (mUser == null) {
+                CharSequence displayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME);
+                mUser = new Person().setName(displayName);
+            }
             mConversationTitle = extras.getCharSequence(EXTRA_CONVERSATION_TITLE);
             Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
             mMessages = Message.getMessagesFromBundleArray(messages);
@@ -6198,7 +6425,7 @@
         public RemoteViews makeContentView(boolean increasedHeight) {
             mBuilder.mOriginalActions = mBuilder.mActions;
             mBuilder.mActions = new ArrayList<>();
-            RemoteViews remoteViews = makeBigContentView();
+            RemoteViews remoteViews = makeBigContentView(true /* showRightIcon */);
             mBuilder.mActions = mBuilder.mOriginalActions;
             mBuilder.mOriginalActions = null;
             return remoteViews;
@@ -6217,7 +6444,7 @@
             for (int i = messages.size() - 1; i >= 0; i--) {
                 Message m = messages.get(i);
                 // Incoming messages have a non-empty sender.
-                if (!TextUtils.isEmpty(m.mSender)) {
+                if (m.mSender != null && !TextUtils.isEmpty(m.mSender.getName())) {
                     return m;
                 }
             }
@@ -6233,23 +6460,31 @@
          */
         @Override
         public RemoteViews makeBigContentView() {
+            return makeBigContentView(false /* showRightIcon */);
+        }
+
+        @NonNull
+        private RemoteViews makeBigContentView(boolean showRightIcon) {
             CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
                     ? super.mBigContentTitle
                     : mConversationTitle;
             boolean isOneToOne = TextUtils.isEmpty(conversationTitle);
-            if (isOneToOne) {
-                // Let's add the conversationTitle in case we didn't have one before and all
-                // messages are from the same sender
-                conversationTitle = createConversationTitleFromMessages();
-            } else if (hasOnlyWhiteSpaceSenders()) {
+            if (hasOnlyWhiteSpaceSenders()) {
                 isOneToOne = true;
             }
-            boolean hasTitle = !TextUtils.isEmpty(conversationTitle);
             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
                     mBuilder.getMessagingLayoutResource(),
                     mBuilder.mParams.reset().hasProgress(false).title(conversationTitle).text(null)
-                            .hideLargeIcon(isOneToOne).alwaysShowReply(true));
+                            .hideLargeIcon(!showRightIcon || isOneToOne)
+                            .headerTextSecondary(conversationTitle)
+                            .alwaysShowReply(showRightIcon));
             addExtras(mBuilder.mN.extras);
+            // also update the end margin if there is an image
+            int endMargin = R.dimen.notification_content_margin_end;
+            if (mBuilder.mN.hasLargeIcon() && showRightIcon) {
+                endMargin = R.dimen.notification_content_plus_picture_margin_end;
+            }
+            contentView.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
                     mBuilder.resolveContrastColor());
             contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
@@ -6264,8 +6499,8 @@
         private boolean hasOnlyWhiteSpaceSenders() {
             for (int i = 0; i < mMessages.size(); i++) {
                 Message m = mMessages.get(i);
-                CharSequence sender = m.getSender();
-                if (!isWhiteSpace(sender)) {
+                Person sender = m.getSenderPerson();
+                if (sender != null && !isWhiteSpace(sender.getName())) {
                     return false;
                 }
             }
@@ -6294,9 +6529,9 @@
             ArraySet<CharSequence> names = new ArraySet<>();
             for (int i = 0; i < mMessages.size(); i++) {
                 Message m = mMessages.get(i);
-                CharSequence sender = m.getSender();
+                Person sender = m.getSenderPerson();
                 if (sender != null) {
-                    names.add(sender);
+                    names.add(sender.getName());
                 }
             }
             SpannableStringBuilder title = new SpannableStringBuilder();
@@ -6316,7 +6551,7 @@
          */
         @Override
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
-            RemoteViews remoteViews = makeBigContentView();
+            RemoteViews remoteViews = makeBigContentView(true /* showRightIcon */);
             remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
             return remoteViews;
         }
@@ -6331,13 +6566,15 @@
             static final String KEY_TEXT = "text";
             static final String KEY_TIMESTAMP = "time";
             static final String KEY_SENDER = "sender";
+            static final String KEY_SENDER_PERSON = "sender_person";
             static final String KEY_DATA_MIME_TYPE = "type";
             static final String KEY_DATA_URI= "uri";
             static final String KEY_EXTRAS_BUNDLE = "extras";
 
             private final CharSequence mText;
             private final long mTimestamp;
-            private final CharSequence mSender;
+            @Nullable
+            private final Person mSender;
 
             private Bundle mExtras = new Bundle();
             private String mDataMimeType;
@@ -6352,8 +6589,28 @@
              * the platform will insert {@link MessagingStyle#getUserDisplayName()}.
              * Should be unique amongst all individuals in the conversation, and should be
              * consistent during re-posts of the notification.
+             *
+             *  @deprecated use {@code Message(CharSequence, long, Person)}
              */
             public Message(CharSequence text, long timestamp, CharSequence sender){
+                this(text, timestamp, sender == null ? null : new Person().setName(sender));
+            }
+
+            /**
+             * Constructor
+             * @param text A {@link CharSequence} to be displayed as the message content
+             * @param timestamp Time at which the message arrived
+             * @param sender The {@link Person} who sent the message.
+             * Should be <code>null</code> for messages by the current user, in which case
+             * the platform will insert the user set in {@code MessagingStyle(Person)}.
+             * <p>
+             * The person provided should contain an Icon, set with {@link Person#setIcon(Icon)}
+             * and also have a name provided with {@link Person#setName(CharSequence)}. If multiple
+             * users have the same name, consider providing a key with {@link Person#setKey(String)}
+             * in order to differentiate between the different users.
+             * </p>
+             */
+            public Message(CharSequence text, long timestamp, @Nullable Person sender){
                 mText = text;
                 mTimestamp = timestamp;
                 mSender = sender;
@@ -6416,8 +6673,18 @@
 
             /**
              * Get the text used to display the contact's name in the messaging experience
+             *
+             * @deprecated use {@link #getSenderPerson()}
              */
             public CharSequence getSender() {
+                return mSender == null ? null : mSender.getName();
+            }
+
+            /**
+             * Get the sender associated with this message.
+             */
+            @Nullable
+            public Person getSenderPerson() {
                 return mSender;
             }
 
@@ -6443,7 +6710,9 @@
                 }
                 bundle.putLong(KEY_TIMESTAMP, mTimestamp);
                 if (mSender != null) {
-                    bundle.putCharSequence(KEY_SENDER, mSender);
+                    // Legacy listeners need this
+                    bundle.putCharSequence(KEY_SENDER, mSender.getName());
+                    bundle.putParcelable(KEY_SENDER_PERSON, mSender);
                 }
                 if (mDataMimeType != null) {
                     bundle.putString(KEY_DATA_MIME_TYPE, mDataMimeType);
@@ -6492,8 +6761,20 @@
                     if (!bundle.containsKey(KEY_TEXT) || !bundle.containsKey(KEY_TIMESTAMP)) {
                         return null;
                     } else {
+
+                        Person senderPerson = bundle.getParcelable(KEY_SENDER_PERSON);
+                        if (senderPerson == null) {
+                            // Legacy apps that use compat don't actually provide the sender objects
+                            // We need to fix the compat version to provide people / use
+                            // the native api instead
+                            CharSequence senderName = bundle.getCharSequence(KEY_SENDER);
+                            if (senderName != null) {
+                                senderPerson = new Person().setName(senderName);
+                            }
+                        }
                         Message message = new Message(bundle.getCharSequence(KEY_TEXT),
-                                bundle.getLong(KEY_TIMESTAMP), bundle.getCharSequence(KEY_SENDER));
+                                bundle.getLong(KEY_TIMESTAMP),
+                                senderPerson);
                         if (bundle.containsKey(KEY_DATA_MIME_TYPE) &&
                                 bundle.containsKey(KEY_DATA_URI)) {
                             message.setData(bundle.getString(KEY_DATA_MIME_TYPE),
@@ -7128,6 +7409,176 @@
         }
     }
 
+    /**
+     * A Person associated with this Notification.
+     */
+    public static final class Person implements Parcelable {
+        @Nullable private CharSequence mName;
+        @Nullable private Icon mIcon;
+        @Nullable private String mUri;
+        @Nullable private String mKey;
+
+        protected Person(Parcel in) {
+            mName = in.readCharSequence();
+            if (in.readInt() != 0) {
+                mIcon = Icon.CREATOR.createFromParcel(in);
+            }
+            mUri = in.readString();
+            mKey = in.readString();
+        }
+
+        /**
+         * Create a new person.
+         */
+        public Person() {
+        }
+
+        /**
+         * Give this person a name.
+         *
+         * @param name the name of this person
+         */
+        public Person setName(@Nullable CharSequence name) {
+            this.mName = name;
+            return this;
+        }
+
+        /**
+         * Add an icon for this person.
+         * <br />
+         * This is currently only used for {@link MessagingStyle} notifications and should not be
+         * provided otherwise, in order to save memory. The system will prefer this icon over any
+         * images that are resolved from the URI.
+         *
+         * @param icon the icon of the person
+         */
+        public Person setIcon(@Nullable Icon icon) {
+            this.mIcon = icon;
+            return this;
+        }
+
+        /**
+         * Set a URI associated with this person.
+         *
+         * <P>
+         * Depending on user preferences, adding a URI to a Person may allow the notification to
+         * pass through interruption filters, if this notification is of
+         * category {@link #CATEGORY_CALL} or {@link #CATEGORY_MESSAGE}.
+         * The addition of people may also cause this notification to appear more prominently in
+         * the user interface.
+         * </P>
+         *
+         * <P>
+         * The person should be specified by the {@code String} representation of a
+         * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
+         * </P>
+         *
+         * <P>The system will also attempt to resolve {@code mailto:} and {@code tel:} schema
+         * URIs.  The path part of these URIs must exist in the contacts database, in the
+         * appropriate column, or the reference will be discarded as invalid. Telephone schema
+         * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}.
+         * </P>
+         *
+         * @param uri a URI for the person
+         */
+        public Person setUri(@Nullable String uri) {
+            mUri = uri;
+            return this;
+        }
+
+        /**
+         * Add a key to this person in order to uniquely identify it.
+         * This is especially useful if the name doesn't uniquely identify this person or if the
+         * display name is a short handle of the actual name.
+         *
+         * <P>If no key is provided, the name serves as as the key for the purpose of
+         * identification.</P>
+         *
+         * @param key the key that uniquely identifies this person
+         */
+        public Person setKey(@Nullable String key) {
+            mKey = key;
+            return this;
+        }
+
+
+        /**
+         * @return the uri provided for this person or {@code null} if no Uri was provided
+         */
+        @Nullable
+        public String getUri() {
+            return mUri;
+        }
+
+        /**
+         * @return the name provided for this person or {@code null} if no name was provided
+         */
+        @Nullable
+        public CharSequence getName() {
+            return mName;
+        }
+
+        /**
+         * @return the icon provided for this person or {@code null} if no icon was provided
+         */
+        @Nullable
+        public Icon getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * @return the key provided for this person or {@code null} if no key was provided
+         */
+        @Nullable
+        public String getKey() {
+            return mKey;
+        }
+
+        /**
+         * @return the URI associated with this person, or "name:mName" otherwise
+         *  @hide
+         */
+        public String resolveToLegacyUri() {
+            if (mUri != null) {
+                return mUri;
+            }
+            if (mName != null) {
+                return "name:" + mName;
+            }
+            return "";
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, @WriteFlags int flags) {
+            dest.writeCharSequence(mName);
+            if (mIcon != null) {
+                dest.writeInt(1);
+                mIcon.writeToParcel(dest, 0);
+            } else {
+                dest.writeInt(0);
+            }
+            dest.writeString(mUri);
+            dest.writeString(mKey);
+        }
+
+        public static final Creator<Person> CREATOR = new Creator<Person>() {
+            @Override
+            public Person createFromParcel(Parcel in) {
+                return new Person(in);
+            }
+
+            @Override
+            public Person[] newArray(int size) {
+                return new Person[size];
+            }
+        };
+    }
+
     // When adding a new Style subclass here, don't forget to update
     // Builder.getNotificationStyleClass.
 
@@ -8567,6 +9018,7 @@
         boolean ambient = false;
         CharSequence title;
         CharSequence text;
+        CharSequence headerTextSecondary;
         boolean hideLargeIcon;
         public boolean alwaysShowReply;
 
@@ -8575,6 +9027,7 @@
             ambient = false;
             title = null;
             text = null;
+            headerTextSecondary = null;
             return this;
         }
 
@@ -8593,6 +9046,11 @@
             return this;
         }
 
+        final StandardTemplateParams headerTextSecondary(CharSequence text) {
+            this.headerTextSecondary = text;
+            return this;
+        }
+
         final StandardTemplateParams alwaysShowReply(boolean alwaysShowReply) {
             this.alwaysShowReply = alwaysShowReply;
             return this;
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index d523427..a295c4c 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -55,14 +55,24 @@
      */
     public final String agent;
 
+    /**
+     * Whether the {@link agent} should be attached early (before bind-application) or during
+     * bind-application. Agents attached prior to binding cannot be loaded from the app's APK
+     * directly and must be given as an absolute path (or available in the default LD_LIBRARY_PATH).
+     * Agents attached during bind-application will miss early setup (e.g., resource initialization
+     * and classloader generation), but are searched in the app's library search path.
+     */
+    public final boolean attachAgentDuringBind;
+
     public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop,
-            boolean streaming, String agent) {
+            boolean streaming, String agent, boolean attachAgentDuringBind) {
         profileFile = filename;
         profileFd = fd;
         samplingInterval = interval;
         autoStopProfiler = autoStop;
         streamingOutput = streaming;
         this.agent = agent;
+        this.attachAgentDuringBind = attachAgentDuringBind;
     }
 
     public ProfilerInfo(ProfilerInfo in) {
@@ -72,6 +82,7 @@
         autoStopProfiler = in.autoStopProfiler;
         streamingOutput = in.streamingOutput;
         agent = in.agent;
+        attachAgentDuringBind = in.attachAgentDuringBind;
     }
 
     /**
@@ -110,6 +121,7 @@
         out.writeInt(autoStopProfiler ? 1 : 0);
         out.writeInt(streamingOutput ? 1 : 0);
         out.writeString(agent);
+        out.writeBoolean(attachAgentDuringBind);
     }
 
     public static final Parcelable.Creator<ProfilerInfo> CREATOR =
@@ -132,6 +144,7 @@
         autoStopProfiler = in.readInt() != 0;
         streamingOutput = in.readInt() != 0;
         agent = in.readString();
+        attachAgentDuringBind = in.readBoolean();
     }
 
     @Override
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 8c47598..6ac15a5 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -71,6 +71,8 @@
 
     @GuardedBy("mLock")
     private Map<String, Object> mMap;
+    @GuardedBy("mLock")
+    private Throwable mThrowable;
 
     @GuardedBy("mLock")
     private int mDiskWritesInFlight = 0;
@@ -107,6 +109,7 @@
         mMode = mode;
         mLoaded = false;
         mMap = null;
+        mThrowable = null;
         startLoadFromDisk();
     }
 
@@ -139,13 +142,14 @@
 
         Map<String, Object> map = null;
         StructStat stat = null;
+        Throwable thrown = null;
         try {
             stat = Os.stat(mFile.getPath());
             if (mFile.canRead()) {
                 BufferedInputStream str = null;
                 try {
                     str = new BufferedInputStream(
-                            new FileInputStream(mFile), 16*1024);
+                            new FileInputStream(mFile), 16 * 1024);
                     map = (Map<String, Object>) XmlUtils.readMapXml(str);
                 } catch (Exception e) {
                     Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e);
@@ -154,19 +158,36 @@
                 }
             }
         } catch (ErrnoException e) {
-            /* ignore */
+            // An errno exception means the stat failed. Treat as empty/non-existing by
+            // ignoring.
+        } catch (Throwable t) {
+            thrown = t;
         }
 
         synchronized (mLock) {
             mLoaded = true;
-            if (map != null) {
-                mMap = map;
-                mStatTimestamp = stat.st_mtim;
-                mStatSize = stat.st_size;
-            } else {
-                mMap = new HashMap<>();
+            mThrowable = thrown;
+
+            // It's important that we always signal waiters, even if we'll make
+            // them fail with an exception. The try-finally is pretty wide, but
+            // better safe than sorry.
+            try {
+                if (thrown == null) {
+                    if (map != null) {
+                        mMap = map;
+                        mStatTimestamp = stat.st_mtim;
+                        mStatSize = stat.st_size;
+                    } else {
+                        mMap = new HashMap<>();
+                    }
+                }
+                // In case of a thrown exception, we retain the old map. That allows
+                // any open editors to commit and store updates.
+            } catch (Throwable t) {
+                mThrowable = t;
+            } finally {
+                mLock.notifyAll();
             }
-            mLock.notifyAll();
         }
     }
 
@@ -226,6 +247,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void awaitLoadedLocked() {
         if (!mLoaded) {
             // Raise an explicit StrictMode onReadFromDisk for this
@@ -239,6 +261,9 @@
             } catch (InterruptedException unused) {
             }
         }
+        if (mThrowable != null) {
+            throw new IllegalStateException(mThrowable);
+        }
     }
 
     @Override
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6eb4783..6eafcc4 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -136,6 +136,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.euicc.EuiccCardManager;
 import android.telephony.euicc.EuiccManager;
 import android.util.Log;
 import android.util.StatsManager;
@@ -519,6 +520,13 @@
                 return new EuiccManager(ctx.getOuterContext());
             }});
 
+        registerService(Context.EUICC_CARD_SERVICE, EuiccCardManager.class,
+                new CachedServiceFetcher<EuiccCardManager>() {
+                    @Override
+                    public EuiccCardManager createService(ContextImpl ctx) {
+                        return new EuiccCardManager(ctx.getOuterContext());
+                    }});
+
         registerService(Context.UI_MODE_SERVICE, UiModeManager.class,
                 new CachedServiceFetcher<UiModeManager>() {
             @Override
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 8f01685..ba39740 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -24,7 +24,6 @@
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -47,10 +46,14 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
+
+import com.android.internal.util.CollectionUtils;
+
 import libcore.io.IoUtils;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 
@@ -580,6 +583,8 @@
         // Execute the command *without* the lock being held.
         command.run();
 
+        List<AccessibilityEvent> eventsReceived = Collections.emptyList();
+
         // Acquire the lock and wait for the event.
         try {
             // Wait for the event.
@@ -600,14 +605,14 @@
                     if (filter.accept(event)) {
                         return event;
                     }
-                    event.recycle();
+                    eventsReceived = CollectionUtils.add(eventsReceived, event);
                 }
                 // Check if timed out and if not wait.
                 final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
                 final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
                 if (remainingTimeMillis <= 0) {
                     throw new TimeoutException("Expected event not received within: "
-                            + timeoutMillis + " ms.");
+                            + timeoutMillis + " ms, among " + eventsReceived);
                 }
                 synchronized (mLock) {
                     if (mEventQueue.isEmpty()) {
@@ -620,6 +625,10 @@
                 }
             }
         } finally {
+            for (int i = 0; i < CollectionUtils.size(eventsReceived); i++) {
+                AccessibilityEvent event = eventsReceived.get(i);
+                event.recycle();
+            }
             synchronized (mLock) {
                 mWaitingForEventDelivery = false;
                 mEventQueue.clear();
diff --git a/core/java/android/app/admin/ConnectEvent.java b/core/java/android/app/admin/ConnectEvent.java
index f06a925..d511c57 100644
--- a/core/java/android/app/admin/ConnectEvent.java
+++ b/core/java/android/app/admin/ConnectEvent.java
@@ -68,7 +68,7 @@
 
     @Override
     public String toString() {
-        return String.format("ConnectEvent(%s, %d, %d, %s)", mIpAddress, mPort, mTimestamp,
+        return String.format("ConnectEvent(%d, %s, %d, %d, %s)", mId, mIpAddress, mPort, mTimestamp,
                 mPackageName);
     }
 
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 2e697ac..aa05b76 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -29,10 +29,14 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.UserHandle;
 import android.security.KeyChain;
 
+import libcore.util.NonNull;
+import libcore.util.Nullable;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -438,6 +442,31 @@
     //  TO DO: describe syntax.
     public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
 
+    /**
+     * Broadcast action: notify the newly transferred administrator that the transfer
+     * from the original administrator was successful.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_TRANSFER_OWNERSHIP_COMPLETE =
+            "android.app.action.TRANSFER_OWNERSHIP_COMPLETE";
+
+    /**
+     * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
+     * allows a mobile device management application to pass data to the management application
+     * instance after owner transfer.
+     *
+     * <p>
+     * If the transfer is successful, the new device owner receives the data in
+     * {@link DeviceAdminReceiver#onTransferOwnershipComplete(Context, PersistableBundle)}.
+     * The bundle is not changed during the ownership transfer.
+     *
+     * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
+     */
+    public static final String EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE =
+            "android.app.extra.TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE";
+
     private DevicePolicyManager mManager;
     private ComponentName mWho;
 
@@ -860,6 +889,20 @@
      }
 
     /**
+     * Called on the newly assigned owner (either device owner or profile owner) when the ownership
+     * transfer has completed successfully.
+     *
+     * <p> The {@code bundle} parameter allows the original owner to pass data
+     * to the new one.
+     *
+     * @param context the running context as per {@link #onReceive}
+     * @param bundle the data to be passed to the new owner
+     */
+    public void onTransferOwnershipComplete(@NonNull Context context,
+            @Nullable PersistableBundle bundle) {
+    }
+
+    /**
      * Intercept standard device administrator broadcasts.  Implementations
      * should not override this method; it is better to implement the
      * convenience callbacks for each action.
@@ -921,6 +964,10 @@
             onUserAdded(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
         } else if (ACTION_USER_REMOVED.equals(action)) {
             onUserRemoved(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+        } else if (ACTION_TRANSFER_OWNERSHIP_COMPLETE.equals(action)) {
+            PersistableBundle bundle =
+                    intent.getParcelableExtra(EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE);
+            onTransferOwnershipComplete(context, bundle);
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 76c078e..67b59f6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1124,6 +1124,7 @@
      *
      * This broadcast is sent only to the primary user.
      * @see #ACTION_PROVISION_MANAGED_DEVICE
+     * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_DEVICE_OWNER_CHANGED
@@ -1253,6 +1254,26 @@
             = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
 
     /**
+     * Broadcast action to notify ManagedProvisioning that
+     * {@link UserManager#DISALLOW_SHARE_INTO_MANAGED_PROFILE} restriction has changed.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DATA_SHARING_RESTRICTION_CHANGED =
+            "android.app.action.DATA_SHARING_RESTRICTION_CHANGED";
+
+    /**
+     * Broadcast action from ManagedProvisioning to notify that the latest change to
+     * {@link UserManager#DISALLOW_SHARE_INTO_MANAGED_PROFILE} restriction has been successfully
+     * applied (cross profile intent filters updated). Only usesd for CTS tests.
+     * @hide
+     */
+    @TestApi
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED =
+            "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
+
+    /**
      * Permission policy to prompt user for new permission requests for runtime permissions.
      * Already granted or denied permissions are not affected by this.
      */
@@ -1709,6 +1730,16 @@
     public static final int ID_TYPE_MEID = 8;
 
     /**
+     * Broadcast action: sent when the profile owner is set, changed or cleared.
+     *
+     * This broadcast is sent only to the user managed by the new profile owner.
+     * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PROFILE_OWNER_CHANGED =
+            "android.app.action.PROFILE_OWNER_CHANGED";
+
+    /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
      * @param admin The administrator component to check for.
@@ -6046,6 +6077,13 @@
      * Called by a profile owner of a managed profile to remove the cross-profile intent filters
      * that go from the managed profile to the parent, or from the parent to the managed profile.
      * Only removes those that have been set by the profile owner.
+     * <p>
+     * <em>Note</em>: A list of default cross profile intent filters are set up by the system when
+     * the profile is created, some of them ensure the proper functioning of the profile, while
+     * others enable sharing of data from the parent to the managed profile for user convenience.
+     * These default intent filters are not cleared when this API is called. If the default cross
+     * profile data sharing is not desired, they can be disabled with
+     * {@link UserManager#DISALLOW_SHARE_INTO_MANAGED_PROFILE}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
@@ -6468,12 +6506,6 @@
     public static final int MAKE_USER_DEMO = 0x0004;
 
     /**
-     * Flag used by {@link #createAndManageUser} to specify that the newly created user should be
-     * started in the background as part of the user creation.
-     */
-    public static final int START_USER_IN_BACKGROUND = 0x0008;
-
-    /**
      * Flag used by {@link #createAndManageUser} to specify that the newly created user should skip
      * the disabling of system apps during provisioning.
      */
@@ -6486,7 +6518,6 @@
             SKIP_SETUP_WIZARD,
             MAKE_USER_EPHEMERAL,
             MAKE_USER_DEMO,
-            START_USER_IN_BACKGROUND,
             LEAVE_ALL_SYSTEM_APPS_ENABLED
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -6515,7 +6546,8 @@
      *            IllegalArgumentException is thrown.
      * @param adminExtras Extras that will be passed to onEnable of the admin receiver on the new
      *            user.
-     * @param flags {@link #SKIP_SETUP_WIZARD} is supported.
+     * @param flags {@link #SKIP_SETUP_WIZARD}, {@link #MAKE_USER_EPHEMERAL} and
+     *        {@link #LEAVE_ALL_SYSTEM_APPS_ENABLED} are supported.
      * @see UserHandle
      * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the
      *         user could not be created.
@@ -6534,8 +6566,8 @@
     }
 
     /**
-     * Called by a device owner to remove a user and all associated data. The primary user can not
-     * be removed.
+     * Called by a device owner to remove a user/profile and all associated data. The primary user
+     * can not be removed.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param userHandle the user to remove.
@@ -6552,14 +6584,14 @@
     }
 
     /**
-     * Called by a device owner to switch the specified user to the foreground.
-     * <p> This cannot be used to switch to a managed profile.
+     * Called by a device owner to switch the specified secondary user to the foreground.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param userHandle the user to switch to; null will switch to primary.
      * @return {@code true} if the switch was successful, {@code false} otherwise.
      * @throws SecurityException if {@code admin} is not a device owner.
      * @see Intent#ACTION_USER_FOREGROUND
+     * @see #getSecondaryUsers(ComponentName)
      */
     public boolean switchUser(@NonNull ComponentName admin, @Nullable UserHandle userHandle) {
         throwIfParentInstance("switchUser");
@@ -6571,13 +6603,32 @@
     }
 
     /**
+     * Called by a device owner to start the specified secondary user in background.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param userHandle the user to be stopped.
+     * @return {@code true} if the user can be started, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     * @see #getSecondaryUsers(ComponentName)
+     */
+    public boolean startUserInBackground(
+            @NonNull ComponentName admin, @NonNull UserHandle userHandle) {
+        throwIfParentInstance("startUserInBackground");
+        try {
+            return mService.startUserInBackground(admin, userHandle);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called by a device owner to stop the specified secondary user.
-     * <p> This cannot be used to stop the primary user or a managed profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param userHandle the user to be stopped.
      * @return {@code true} if the user can be stopped, {@code false} otherwise.
      * @throws SecurityException if {@code admin} is not a device owner.
+     * @see #getSecondaryUsers(ComponentName)
      */
     public boolean stopUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) {
         throwIfParentInstance("stopUser");
@@ -6589,14 +6640,13 @@
     }
 
     /**
-     * Called by a profile owner that is affiliated with the device to stop the calling user
-     * and switch back to primary.
-     * <p> This has no effect when called on a managed profile.
+     * Called by a profile owner of secondary user that is affiliated with the device to stop the
+     * calling user and switch back to primary.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return {@code true} if the exit was successful, {@code false} otherwise.
      * @throws SecurityException if {@code admin} is not a profile owner affiliated with the device.
-     * @see #isAffiliatedUser
+     * @see #getSecondaryUsers(ComponentName)
      */
     public boolean logoutUser(@NonNull ComponentName admin) {
         throwIfParentInstance("logoutUser");
@@ -6608,17 +6658,18 @@
     }
 
     /**
-     * Called by a device owner to list all secondary users on the device, excluding managed
-     * profiles.
+     * Called by a device owner to list all secondary users on the device. Managed profiles are not
+     * considered as secondary users.
      * <p> Used for various user management APIs, including {@link #switchUser}, {@link #removeUser}
      * and {@link #stopUser}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return list of other {@link UserHandle}s on the device.
      * @throws SecurityException if {@code admin} is not a device owner.
-     * @see #switchUser
-     * @see #removeUser
-     * @see #stopUser
+     * @see #removeUser(ComponentName, UserHandle)
+     * @see #switchUser(ComponentName, UserHandle)
+     * @see #startUserInBackground(ComponentName, UserHandle)
+     * @see #stopUser(ComponentName, UserHandle)
      */
     public List<UserHandle> getSecondaryUsers(@NonNull ComponentName admin) {
         throwIfParentInstance("getSecondaryUsers");
@@ -8582,6 +8633,13 @@
      *
      * <p> Backup service is off by default when device owner is present.
      *
+     * <p> If backups are made mandatory by specifying a non-null mandatory backup transport using
+     * the {@link DevicePolicyManager#setMandatoryBackupTransport} method, the backup service is
+     * automatically enabled.
+     *
+     * <p> If the backup service is disabled using this method after the mandatory backup transport
+     * has been set, the mandatory backup transport is cleared.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param enabled {@code true} to enable the backup service, {@code false} to disable it.
      * @throws SecurityException if {@code admin} is not a device owner.
@@ -8613,6 +8671,43 @@
     }
 
     /**
+     * Makes backups mandatory and enforces the usage of the specified backup transport.
+     *
+     * <p>When a {@code null} backup transport is specified, backups are made optional again.
+     * <p>Only device owner can call this method.
+     * <p>If backups were disabled and a non-null backup transport {@link ComponentName} is
+     * specified, backups will be enabled.
+     *
+     * @param admin admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param backupTransportComponent The backup transport layer to be used for mandatory backups.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     */
+    public void setMandatoryBackupTransport(
+            @NonNull ComponentName admin, @Nullable ComponentName backupTransportComponent) {
+        try {
+            mService.setMandatoryBackupTransport(admin, backupTransportComponent);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the backup transport which has to be used for backups if backups are mandatory or
+     * {@code null} if backups are not mandatory.
+     *
+     * @return a {@link ComponentName} of the backup transport layer to be used if backups are
+     *         mandatory or {@code null} if backups are not mandatory.
+     */
+    public ComponentName getMandatoryBackupTransport() {
+        try {
+            return mService.getMandatoryBackupTransport();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+
+    /**
      * Called by a device owner to control the network logging feature.
      *
      * <p> Network logs contain DNS lookup and connect() library call events. The following library
@@ -8997,41 +9092,34 @@
         }
     }
 
-    //TODO STOPSHIP Add link to onTransferComplete callback when implemented.
     /**
-     * Transfers the current administrator. All policies from the current administrator are
-     * migrated to the new administrator. The whole operation is atomic - the transfer is either
-     * complete or not done at all.
+     * Changes the current administrator to another one. All policies from the current
+     * administrator are migrated to the new administrator. The whole operation is atomic -
+     * the transfer is either complete or not done at all.
      *
-     * Depending on the current administrator (device owner, profile owner, corporate owned
-     * profile owner), you have the following expected behaviour:
+     * <p>Depending on the current administrator (device owner, profile owner), you have the
+     * following expected behaviour:
      * <ul>
      *     <li>A device owner can only be transferred to a new device owner</li>
      *     <li>A profile owner can only be transferred to a new profile owner</li>
-     *     <li>A corporate owned managed profile can have two cases:
-     *          <ul>
-     *              <li>If the device owner and profile owner are the same package,
-     *              both will be transferred.</li>
-     *              <li>If the device owner and profile owner are different packages,
-     *              and if this method is called from the profile owner, only the profile owner
-     *              is transferred. Similarly, if it is called from the device owner, only
-     *              the device owner is transferred.</li>
-     *          </ul>
-     *     </li>
      * </ul>
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param target Which {@link DeviceAdminReceiver} we want the new administrator to be.
-     * @param bundle Parameters - This bundle allows the current administrator to pass data to the
-     *               new administrator. The parameters will be received in the
-     *               onTransferComplete callback.
-     * @hide
+     * <p>Use the {@code bundle} parameter to pass data to the new administrator. The parameters
+     * will be received in the
+     * {@link DeviceAdminReceiver#onTransferOwnershipComplete(Context, PersistableBundle)} callback.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @param target which {@link DeviceAdminReceiver} we want the new administrator to be
+     * @param bundle data to be sent to the new administrator
+     * @throws SecurityException if {@code admin} is not a device owner nor a profile owner
+     * @throws IllegalArgumentException if {@code admin} or {@code target} is {@code null},
+     * both are components in the same package or {@code target} is not an active admin
      */
-    public void transferOwner(@NonNull ComponentName admin, @NonNull ComponentName target,
+    public void transferOwnership(@NonNull ComponentName admin, @NonNull ComponentName target,
             PersistableBundle bundle) {
-        throwIfParentInstance("transferOwner");
+        throwIfParentInstance("transferOwnership");
         try {
-            mService.transferOwner(admin, target, bundle);
+            mService.transferOwnership(admin, target, bundle);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/DnsEvent.java b/core/java/android/app/admin/DnsEvent.java
index 4ddf13e..a2d704b 100644
--- a/core/java/android/app/admin/DnsEvent.java
+++ b/core/java/android/app/admin/DnsEvent.java
@@ -96,7 +96,7 @@
 
     @Override
     public String toString() {
-        return String.format("DnsEvent(%s, %s, %d, %d, %s)", mHostname,
+        return String.format("DnsEvent(%d, %s, %s, %d, %d, %s)", mId, mHostname,
                 (mIpAddresses == null) ? "NONE" : String.join(" ", mIpAddresses),
                 mIpAddressesCount, mTimestamp, mPackageName);
     }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 5916a62..9cdd1f8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -226,6 +226,7 @@
     UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
     boolean removeUser(in ComponentName who, in UserHandle userHandle);
     boolean switchUser(in ComponentName who, in UserHandle userHandle);
+    boolean startUserInBackground(in ComponentName who, in UserHandle userHandle);
     boolean stopUser(in ComponentName who, in UserHandle userHandle);
     boolean logoutUser(in ComponentName who);
     List<UserHandle> getSecondaryUsers(in ComponentName who);
@@ -358,6 +359,8 @@
 
     void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
     boolean isBackupServiceEnabled(in ComponentName admin);
+    void setMandatoryBackupTransport(in ComponentName admin, in ComponentName backupTransportComponent);
+    ComponentName getMandatoryBackupTransport();
 
     void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled);
     boolean isNetworkLoggingEnabled(in ComponentName admin);
@@ -387,5 +390,5 @@
     boolean isLogoutEnabled();
 
     List<String> getDisallowedSystemApps(in ComponentName admin, int userId, String provisioningAction);
-    void transferOwner(in ComponentName admin, in ComponentName target, in PersistableBundle bundle);
+    void transferOwnership(in ComponentName admin, in ComponentName target, in PersistableBundle bundle);
 }
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index da81d19..3558e34 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -55,6 +55,22 @@
     // Transport should ignore its own moratoriums for call with this flag set.
     public static final int FLAG_USER_INITIATED = 1;
 
+    /**
+     * For key value backup, indicates that the backup data is a diff from a previous backup. The
+     * transport must apply this diff to an existing backup to build the new backup set.
+     *
+     * @hide
+     */
+    public static final int FLAG_INCREMENTAL = 1 << 1;
+
+    /**
+     * For key value backup, indicates that the backup data is a complete set, not a diff from a
+     * previous backup. The transport should clear any previous backup when storing this backup.
+     *
+     * @hide
+     */
+    public static final int FLAG_NON_INCREMENTAL = 1 << 2;
+
     IBackupTransport mBinderImpl = new TransportImpl();
 
     public IBinder getBinder() {
@@ -231,12 +247,18 @@
      * {@link #TRANSPORT_OK}, {@link #finishBackup} will then be called to ensure the data
      * is sent and recorded successfully.
      *
+     * If the backup data is a diff against the previous backup then the flag {@link
+     * BackupTransport#FLAG_INCREMENTAL} will be set. Otherwise, if the data is a complete backup
+     * set then {@link BackupTransport#FLAG_NON_INCREMENTAL} will be set. Before P neither flag will
+     * be set regardless of whether the backup is incremental or not.
+     *
      * @param packageInfo The identity of the application whose data is being backed up.
      *   This specifically includes the signature list for the package.
      * @param inFd Descriptor of file with data that resulted from invoking the application's
      *   BackupService.doBackup() method.  This may be a pipe rather than a file on
      *   persistent media, so it may not be seekable.
-     * @param flags {@link BackupTransport#FLAG_USER_INITIATED} or 0.
+     * @param flags a combination of {@link BackupTransport#FLAG_USER_INITIATED}, {@link
+     *   BackupTransport#FLAG_NON_INCREMENTAL}, {@link BackupTransport#FLAG_INCREMENTAL}, or 0.
      * @return one of {@link BackupTransport#TRANSPORT_OK} (OK so far),
      *  {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED} (to suppress backup of this
      *  specific package, but allow others to proceed),
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 792cb5f..f3ca746 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -294,7 +294,8 @@
      *
      * @param transport ComponentName of the service hosting the transport. This is different from
      *                  the transport's name that is returned by {@link BackupTransport#name()}.
-     * @param listener A listener object to get a callback on the transport being selected.
+     * @param listener A listener object to get a callback on the transport being selected. It may
+     *                 be {@code null}.
      *
      * @hide
      */
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 5053dc6..c71bf2e 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -70,6 +70,7 @@
     private final Network network;
 
     private int stopReason; // Default value of stopReason is REASON_CANCELED
+    private String debugStopReason; // Human readable stop reason for debugging.
 
     /** @hide */
     public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
@@ -104,6 +105,14 @@
     }
 
     /**
+     * Reason onStopJob() was called on this job.
+     * @hide
+     */
+    public String getDebugStopReason() {
+        return debugStopReason;
+    }
+
+    /**
      * @return The extras you passed in when constructing this job with
      * {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will
      * never be null. If you did not set any extras this will be an empty bundle.
@@ -288,11 +297,13 @@
             network = null;
         }
         stopReason = in.readInt();
+        debugStopReason = in.readString();
     }
 
     /** @hide */
-    public void setStopReason(int reason) {
+    public void setStopReason(int reason, String debugStopReason) {
         stopReason = reason;
+        this.debugStopReason = debugStopReason;
     }
 
     @Override
@@ -323,6 +334,7 @@
             dest.writeInt(0);
         }
         dest.writeInt(stopReason);
+        dest.writeString(debugStopReason);
     }
 
     public static final Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index 764ceed..08ad2f0 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -24,6 +24,8 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -54,6 +56,11 @@
     /** Target client activity. Might be null if the entire transaction is targeting an app. */
     private IBinder mActivityToken;
 
+    /** Get the target client of the transaction. */
+    public IApplicationThread getClient() {
+        return mClient;
+    }
+
     /**
      * Add a message to the end of the sequence of callbacks.
      * @param activityCallback A single message that can contain a lifecycle request/callback.
@@ -78,7 +85,8 @@
     }
 
     /** Get the target state lifecycle request. */
-    ActivityLifecycleItem getLifecycleStateRequest() {
+    @VisibleForTesting
+    public ActivityLifecycleItem getLifecycleStateRequest() {
         return mLifecycleStateRequest;
     }
 
diff --git a/core/java/android/app/servertransaction/ObjectPool.java b/core/java/android/app/servertransaction/ObjectPool.java
index 9812125..2fec30a 100644
--- a/core/java/android/app/servertransaction/ObjectPool.java
+++ b/core/java/android/app/servertransaction/ObjectPool.java
@@ -16,8 +16,8 @@
 
 package android.app.servertransaction;
 
+import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.Map;
 
 /**
@@ -27,7 +27,7 @@
 class ObjectPool {
 
     private static final Object sPoolSync = new Object();
-    private static final Map<Class, LinkedList<? extends ObjectPoolItem>> sPoolMap =
+    private static final Map<Class, ArrayList<? extends ObjectPoolItem>> sPoolMap =
             new HashMap<>();
 
     private static final int MAX_POOL_SIZE = 50;
@@ -40,9 +40,9 @@
     public static <T extends ObjectPoolItem> T obtain(Class<T> itemClass) {
         synchronized (sPoolSync) {
             @SuppressWarnings("unchecked")
-            LinkedList<T> itemPool = (LinkedList<T>) sPoolMap.get(itemClass);
+            final ArrayList<T> itemPool = (ArrayList<T>) sPoolMap.get(itemClass);
             if (itemPool != null && !itemPool.isEmpty()) {
-                return itemPool.poll();
+                return itemPool.remove(itemPool.size() - 1);
             }
             return null;
         }
@@ -56,16 +56,20 @@
     public static <T extends ObjectPoolItem> void recycle(T item) {
         synchronized (sPoolSync) {
             @SuppressWarnings("unchecked")
-            LinkedList<T> itemPool = (LinkedList<T>) sPoolMap.get(item.getClass());
+            ArrayList<T> itemPool = (ArrayList<T>) sPoolMap.get(item.getClass());
             if (itemPool == null) {
-                itemPool = new LinkedList<>();
+                itemPool = new ArrayList<>();
                 sPoolMap.put(item.getClass(), itemPool);
             }
-            if (itemPool.contains(item)) {
-                throw new IllegalStateException("Trying to recycle already recycled item");
+            // Check if the item is already in the pool
+            final int size = itemPool.size();
+            for (int i = 0; i < size; i++) {
+                if (itemPool.get(i) == item) {
+                    throw new IllegalStateException("Trying to recycle already recycled item");
+                }
             }
 
-            if (itemPool.size() < MAX_POOL_SIZE) {
+            if (size < MAX_POOL_SIZE) {
                 itemPool.add(item);
             }
         }
diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl
index 506dd12..65b0249 100644
--- a/core/java/android/app/trust/ITrustListener.aidl
+++ b/core/java/android/app/trust/ITrustListener.aidl
@@ -24,4 +24,5 @@
 oneway interface ITrustListener {
     void onTrustChanged(boolean enabled, int userId, int flags);
     void onTrustManagedChanged(boolean managed, int userId);
+    void onTrustError(in CharSequence message);
 }
\ No newline at end of file
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 852cb8e..8ab0b70 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -36,9 +36,11 @@
 
     private static final int MSG_TRUST_CHANGED = 1;
     private static final int MSG_TRUST_MANAGED_CHANGED = 2;
+    private static final int MSG_TRUST_ERROR = 3;
 
     private static final String TAG = "TrustManager";
     private static final String DATA_FLAGS = "initiatedByUser";
+    private static final String DATA_MESSAGE = "message";
 
     private final ITrustManager mService;
     private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
@@ -148,6 +150,13 @@
                     mHandler.obtainMessage(MSG_TRUST_MANAGED_CHANGED, (managed ? 1 : 0), userId,
                             trustListener).sendToTarget();
                 }
+
+                @Override
+                public void onTrustError(CharSequence message) {
+                    Message m = mHandler.obtainMessage(MSG_TRUST_ERROR);
+                    m.getData().putCharSequence(DATA_MESSAGE, message);
+                    m.sendToTarget();
+                }
             };
             mService.registerTrustListener(iTrustListener);
             mTrustListeners.put(trustListener, iTrustListener);
@@ -221,6 +230,10 @@
                     break;
                 case MSG_TRUST_MANAGED_CHANGED:
                     ((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2);
+                    break;
+                case MSG_TRUST_ERROR:
+                    final CharSequence message = msg.peekData().getCharSequence(DATA_MESSAGE);
+                    ((TrustListener)msg.obj).onTrustError(message);
             }
         }
     };
@@ -229,9 +242,9 @@
 
         /**
          * Reports that the trust state has changed.
-         * @param enabled if true, the system believes the environment to be trusted.
-         * @param userId the user, for which the trust changed.
-         * @param flags flags specified by the trust agent when granting trust. See
+         * @param enabled If true, the system believes the environment to be trusted.
+         * @param userId The user, for which the trust changed.
+         * @param flags Flags specified by the trust agent when granting trust. See
          *     {@link android.service.trust.TrustAgentService#grantTrust(CharSequence, long, int)
          *                 TrustAgentService.grantTrust(CharSequence, long, int)}.
          */
@@ -239,9 +252,15 @@
 
         /**
          * Reports that whether trust is managed has changed
-         * @param enabled if true, at least one trust agent is managing trust.
-         * @param userId the user, for which the state changed.
+         * @param enabled If true, at least one trust agent is managing trust.
+         * @param userId The user, for which the state changed.
          */
         void onTrustManagedChanged(boolean enabled, int userId);
+
+        /**
+         * Reports that an error happened on a TrustAgentService.
+         * @param message A message that should be displayed on the UI.
+         */
+        void onTrustError(CharSequence message);
     }
 }
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 93e14de..5cd0981 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -22,6 +22,7 @@
 import android.content.res.Configuration;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * UsageStatsManager local system service interface.
@@ -159,6 +160,22 @@
     public abstract void applyRestoredPayload(@UserIdInt int userId, String key, byte[] payload);
 
     /**
+     * Called by DevicePolicyManagerService to inform that a new admin has been added.
+     *
+     * @param packageName the package in which the admin component is part of.
+     * @param userId the userId in which the admin has been added.
+     */
+    public abstract void onActiveAdminAdded(String packageName, int userId);
+
+    /**
+     * Called by DevicePolicyManagerService to inform about the active admins in an user.
+     *
+     * @param adminApps the set of active admins in {@param userId} or null if there are none.
+     * @param userId the userId to which the admin apps belong.
+     */
+    public abstract void setActiveAdminApps(Set<String> adminApps, int userId);
+
+    /**
      * Return usage stats.
      *
      * @param obfuscateInstantApps whether instant app package names need to be obfuscated in the
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index ad7a93c..9b736b7 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -618,6 +618,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int ACCESS_UNKNOWN = 0;
 
     /**
@@ -626,6 +627,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int ACCESS_ALLOWED = 1;
 
     /**
@@ -634,6 +636,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int ACCESS_REJECTED = 2;
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index c94540a..a68f485 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -556,8 +556,8 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
-     * Priority can be one of {@link #PRIORITY_ON} or
-     * {@link #PRIORITY_OFF},
+     * Priority can be one of {@link BluetoothProfile#PRIORITY_ON} or
+     * {@link BluetoothProfile#PRIORITY_OFF},
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
      * permission.
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 41cf809..0e2263f 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -19,6 +19,7 @@
 
 import android.Manifest;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 
 import java.util.List;
 
@@ -185,6 +186,7 @@
      *
      * @hide
      **/
+    @SystemApi
     public static final int PRIORITY_ON = 100;
 
     /**
@@ -193,6 +195,7 @@
      *
      * @hide
      **/
+    @SystemApi
     public static final int PRIORITY_OFF = 0;
 
     /**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 06f9171..f69e764 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3223,7 +3223,7 @@
     public abstract @Nullable String getSystemServiceName(@NonNull Class<?> serviceClass);
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.os.PowerManager} for controlling power management,
      * including "wake locks," which let you keep the device on while
      * you're running long tasks.
@@ -3231,117 +3231,117 @@
     public static final String POWER_SERVICE = "power";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.os.RecoverySystem} for accessing the recovery system
      * service.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @hide
      */
     public static final String RECOVERY_SERVICE = "recovery";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.WindowManager} for accessing the system's window
      * manager.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.view.WindowManager
      */
     public static final String WINDOW_SERVICE = "window";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.LayoutInflater} for inflating layout resources in this
      * context.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.view.LayoutInflater
      */
     public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.accounts.AccountManager} for receiving intents at a
      * time of your choosing.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.accounts.AccountManager
      */
     public static final String ACCOUNT_SERVICE = "account";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.app.ActivityManager} for interacting with the global
      * system state.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.ActivityManager
      */
     public static final String ACTIVITY_SERVICE = "activity";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.app.AlarmManager} for receiving intents at a
      * time of your choosing.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.AlarmManager
      */
     public static final String ALARM_SERVICE = "alarm";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.app.NotificationManager} for informing the user of
      * background events.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.NotificationManager
      */
     public static final String NOTIFICATION_SERVICE = "notification";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.accessibility.AccessibilityManager} for giving the user
      * feedback for UI events through the registered event listeners.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.view.accessibility.AccessibilityManager
      */
     public static final String ACCESSIBILITY_SERVICE = "accessibility";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.accessibility.CaptioningManager} for obtaining
      * captioning properties and listening for changes in captioning
      * preferences.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.view.accessibility.CaptioningManager
      */
     public static final String CAPTIONING_SERVICE = "captioning";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.app.NotificationManager} for controlling keyguard.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.KeyguardManager
      */
     public static final String KEYGUARD_SERVICE = "keyguard";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.location.LocationManager} for controlling location
      * updates.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.location.LocationManager
      */
     public static final String LOCATION_SERVICE = "location";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.location.CountryDetector} for detecting the country that
      * the user is in.
      *
@@ -3350,96 +3350,96 @@
     public static final String COUNTRY_DETECTOR = "country_detector";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.app.SearchManager} for handling searches.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.SearchManager
      */
     public static final String SEARCH_SERVICE = "search";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.hardware.SensorManager} for accessing sensors.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.SensorManager
      */
     public static final String SENSOR_SERVICE = "sensor";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.os.storage.StorageManager} for accessing system storage
      * functions.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.os.storage.StorageManager
      */
     public static final String STORAGE_SERVICE = "storage";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.app.usage.StorageStatsManager} for accessing system storage
      * statistics.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.usage.StorageStatsManager
      */
     public static final String STORAGE_STATS_SERVICE = "storagestats";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * com.android.server.WallpaperService for accessing wallpapers.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String WALLPAPER_SERVICE = "wallpaper";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.os.Vibrator} for interacting with the vibration hardware.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.os.Vibrator
      */
     public static final String VIBRATOR_SERVICE = "vibrator";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.app.StatusBarManager} for interacting with the status bar.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.StatusBarManager
      * @hide
      */
     public static final String STATUS_BAR_SERVICE = "statusbar";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.ConnectivityManager} for handling management of
      * network connections.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.ConnectivityManager
      */
     public static final String CONNECTIVITY_SERVICE = "connectivity";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
      * IPSec.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String IPSEC_SERVICE = "ipsec";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.os.IUpdateLock} for managing runtime sequences that
      * must not be interrupted by headless OTA application or similar.
      *
      * @hide
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.os.UpdateLock
      */
     public static final String UPDATE_LOCK_SERVICE = "updatelock";
@@ -3451,18 +3451,18 @@
     public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link com.android.server.slice.SliceManagerService} for managing slices.
      * @hide
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String SLICE_SERVICE = "slice";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.app.usage.NetworkStatsManager} for querying network usage stats.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.usage.NetworkStatsManager
      */
     public static final String NETWORK_STATS_SERVICE = "netstats";
@@ -3472,40 +3472,40 @@
     public static final String NETWORK_WATCHLIST_SERVICE = "network_watchlist";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.wifi.WifiManager} for handling management of
      * Wi-Fi access.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.wifi.WifiManager
      */
     public static final String WIFI_SERVICE = "wifi";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.wifi.p2p.WifiP2pManager} for handling management of
      * Wi-Fi peer-to-peer connections.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.wifi.p2p.WifiP2pManager
      */
     public static final String WIFI_P2P_SERVICE = "wifip2p";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.net.wifi.aware.WifiAwareManager} for handling management of
      * Wi-Fi Aware.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.wifi.aware.WifiAwareManager
      */
     public static final String WIFI_AWARE_SERVICE = "wifiaware";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.wifi.WifiScanner} for scanning the wifi universe
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.wifi.WifiScanner
      * @hide
      */
@@ -3513,10 +3513,10 @@
     public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.wifi.RttManager} for ranging devices with wifi
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.wifi.RttManager
      * @hide
      */
@@ -3524,23 +3524,23 @@
     public static final String WIFI_RTT_SERVICE = "rttmanager";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.wifi.rtt.WifiRttManager} for ranging devices with wifi
      *
      * Note: this is a replacement for WIFI_RTT_SERVICE above. It will
      * be renamed once final implementation in place.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.wifi.rtt.WifiRttManager
      */
     public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.lowpan.LowpanManager} for handling management of
      * LoWPAN access.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.lowpan.LowpanManager
      *
      * @hide
@@ -3548,11 +3548,11 @@
     public static final String LOWPAN_SERVICE = "lowpan";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.EthernetManager} for handling management of
      * Ethernet access.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.EthernetManager
      *
      * @hide
@@ -3560,98 +3560,98 @@
     public static final String ETHERNET_SERVICE = "ethernet";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.nsd.NsdManager} for handling management of network service
      * discovery
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.nsd.NsdManager
      */
     public static final String NSD_SERVICE = "servicediscovery";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.media.AudioManager} for handling management of volume,
      * ringer modes and audio routing.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.media.AudioManager
      */
     public static final String AUDIO_SERVICE = "audio";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.fingerprint.FingerprintManager} for handling management
      * of fingerprints.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.fingerprint.FingerprintManager
      */
     public static final String FINGERPRINT_SERVICE = "fingerprint";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.media.MediaRouter} for controlling and managing
      * routing of media.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.media.MediaRouter
      */
     public static final String MEDIA_ROUTER_SERVICE = "media_router";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.media.session.MediaSessionManager} for managing media Sessions.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.media.session.MediaSessionManager
      */
     public static final String MEDIA_SESSION_SERVICE = "media_session";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.telephony.TelephonyManager} for handling management the
      * telephony features of the device.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.telephony.TelephonyManager
      */
     public static final String TELEPHONY_SERVICE = "phone";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.telephony.SubscriptionManager} for handling management the
      * telephony subscriptions of the device.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.telephony.SubscriptionManager
      */
     public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.telecom.TelecomManager} to manage telecom-related features
      * of the device.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.telecom.TelecomManager
      */
     public static final String TELECOM_SERVICE = "telecom";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.telephony.CarrierConfigManager} for reading carrier configuration values.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.telephony.CarrierConfigManager
      */
     public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.telephony.euicc.EuiccManager} to manage the device eUICC (embedded SIM).
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.telephony.euicc.EuiccManager
      * TODO(b/35851809): Unhide this API.
      * @hide
@@ -3659,47 +3659,58 @@
     public static final String EUICC_SERVICE = "euicc_service";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.telephony.euicc.EuiccCardManager} to access the device eUICC (embedded SIM).
+     *
+     * @see #getSystemService(String)
+     * @see android.telephony.euicc.EuiccCardManager
+     * TODO(b/35851809): Make this a SystemApi.
+     * @hide
+     */
+    public static final String EUICC_CARD_SERVICE = "euicc_card_service";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.content.ClipboardManager} for accessing and modifying
      * the contents of the global clipboard.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.content.ClipboardManager
      */
     public static final String CLIPBOARD_SERVICE = "clipboard";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link TextClassificationManager} for text classification services.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see TextClassificationManager
      */
     public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.inputmethod.InputMethodManager} for accessing input
      * methods.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String INPUT_METHOD_SERVICE = "input_method";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.textservice.TextServicesManager} for accessing
      * text services.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.appwidget.AppWidgetManager} for accessing AppWidgets.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String APPWIDGET_SERVICE = "appwidget";
 
@@ -3707,7 +3718,7 @@
      * Official published name of the (internal) voice interaction manager service.
      *
      * @hide
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction";
 
@@ -3715,119 +3726,119 @@
      * Official published name of the (internal) autofill service.
      *
      * @hide
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String AUTOFILL_MANAGER_SERVICE = "autofill";
 
     /**
-     * Use with {@link #getSystemService} to access the
+     * Use with {@link #getSystemService(String)} to access the
      * {@link com.android.server.voiceinteraction.SoundTriggerService}.
      *
      * @hide
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String SOUND_TRIGGER_SERVICE = "soundtrigger";
 
 
     /**
-     * Use with {@link #getSystemService} to retrieve an
+     * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.app.backup.IBackupManager IBackupManager} for communicating
      * with the backup mechanism.
      * @hide
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     @SystemApi
     public static final String BACKUP_SERVICE = "backup";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.os.DropBoxManager} instance for recording
      * diagnostic logs.
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String DROPBOX_SERVICE = "dropbox";
 
     /**
      * System service name for the DeviceIdleController.  There is no Java API for this.
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @hide
      */
     public static final String DEVICE_IDLE_CONTROLLER = "deviceidle";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.app.admin.DevicePolicyManager} for working with global
      * device policy management.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String DEVICE_POLICY_SERVICE = "device_policy";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.app.UiModeManager} for controlling UI modes.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String UI_MODE_SERVICE = "uimode";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.app.DownloadManager} for requesting HTTP downloads.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String DOWNLOAD_SERVICE = "download";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.os.BatteryManager} for managing battery state.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String BATTERY_SERVICE = "batterymanager";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.nfc.NfcManager} for using NFC.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String NFC_SERVICE = "nfc";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.bluetooth.BluetoothManager} for using Bluetooth.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String BLUETOOTH_SERVICE = "bluetooth";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.net.sip.SipManager} for accessing the SIP related service.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     /** @hide */
     public static final String SIP_SERVICE = "sip";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.hardware.usb.UsbManager} for access to USB devices (as a USB host)
      * and for controlling this device's behavior as a USB device.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.usb.UsbManager
      */
     public static final String USB_SERVICE = "usb";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.hardware.SerialManager} for access to serial ports.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.SerialManager
      *
      * @hide
@@ -3835,11 +3846,11 @@
     public static final String SERIAL_SERVICE = "serial";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.hdmi.HdmiControlManager} for controlling and managing
      * HDMI-CEC protocol.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.hdmi.HdmiControlManager
      * @hide
      */
@@ -3847,67 +3858,67 @@
     public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.input.InputManager} for interacting with input devices.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.input.InputManager
      */
     public static final String INPUT_SERVICE = "input";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.display.DisplayManager} for interacting with display devices.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.display.DisplayManager
      */
     public static final String DISPLAY_SERVICE = "display";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.os.UserManager} for managing users on devices that support multiple users.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.os.UserManager
      */
     public static final String USER_SERVICE = "user";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.content.pm.LauncherApps} for querying and monitoring launchable apps across
      * profiles of a user.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.content.pm.LauncherApps
      */
     public static final String LAUNCHER_APPS_SERVICE = "launcherapps";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.content.RestrictionsManager} for retrieving application restrictions
      * and requesting permissions for restricted operations.
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.content.RestrictionsManager
      */
     public static final String RESTRICTIONS_SERVICE = "restrictions";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.app.AppOpsManager} for tracking application operations
      * on the device.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.AppOpsManager
      */
     public static final String APP_OPS_SERVICE = "appops";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.camera2.CameraManager} for interacting with
      * camera devices.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.camera2.CameraManager
      */
     public static final String CAMERA_SERVICE = "camera";
@@ -3916,51 +3927,51 @@
      * {@link android.print.PrintManager} for printing and managing
      * printers and print tasks.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.print.PrintManager
      */
     public static final String PRINT_SERVICE = "print";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.companion.CompanionDeviceManager} for managing companion devices
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.companion.CompanionDeviceManager
      */
     public static final String COMPANION_DEVICE_SERVICE = "companiondevice";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.ConsumerIrManager} for transmitting infrared
      * signals from the device.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.ConsumerIrManager
      */
     public static final String CONSUMER_IR_SERVICE = "consumer_ir";
 
     /**
      * {@link android.app.trust.TrustManager} for managing trust agents.
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.trust.TrustManager
      * @hide
      */
     public static final String TRUST_SERVICE = "trust";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.media.tv.TvInputManager} for interacting with TV inputs
      * on the device.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.media.tv.TvInputManager
      */
     public static final String TV_INPUT_SERVICE = "tv_input";
 
     /**
      * {@link android.net.NetworkScoreManager} for managing network scoring.
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.net.NetworkScoreManager
      * @hide
      */
@@ -3968,29 +3979,29 @@
     public static final String NETWORK_SCORE_SERVICE = "network_score";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.app.usage.UsageStatsManager} for querying device usage stats.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.usage.UsageStatsManager
      */
     public static final String USAGE_STATS_SERVICE = "usagestats";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.app.job.JobScheduler} instance for managing occasional
      * background tasks.
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.app.job.JobScheduler
      */
     public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.service.persistentdata.PersistentDataBlockManager} instance
      * for interacting with a storage device that lives across factory resets.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.service.persistentdata.PersistentDataBlockManager
      * @hide
      */
@@ -3998,10 +4009,10 @@
     public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.service.oemlock.OemLockManager} instance for managing the OEM lock.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.service.oemlock.OemLockManager
      * @hide
      */
@@ -4009,54 +4020,54 @@
     public static final String OEM_LOCK_SERVICE = "oem_lock";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.media.projection.MediaProjectionManager} instance for managing
      * media projection sessions.
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.media.projection.MediaProjectionManager
      */
     public static final String MEDIA_PROJECTION_SERVICE = "media_projection";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.media.midi.MidiManager} for accessing the MIDI service.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String MIDI_SERVICE = "midi";
 
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.radio.RadioManager} for accessing the broadcast radio service.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @hide
      */
     public static final String RADIO_SERVICE = "broadcastradio";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.os.HardwarePropertiesManager} for accessing the hardware properties service.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.content.pm.ShortcutManager} for accessing the launcher shortcut service.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.content.pm.ShortcutManager
      */
     public static final String SHORTCUT_SERVICE = "shortcut";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.hardware.location.ContextHubManager} for accessing context hubs.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.hardware.location.ContextHubManager
      *
      * @hide
@@ -4065,11 +4076,11 @@
     public static final String CONTEXTHUB_SERVICE = "contexthub";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.os.health.SystemHealthManager} for accessing system health (battery, power,
      * memory, etc) metrics.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
 
@@ -4098,46 +4109,46 @@
     public static final String STATS_COMPANION_SERVICE = "statscompanion";
 
     /**
-     * Use with {@link #getSystemService} to retrieve an {@link android.stats.StatsManager}.
+     * Use with {@link #getSystemService(String)} to retrieve an {@link android.stats.StatsManager}.
      * @hide
      */
     @SystemApi
     public static final String STATS_MANAGER = "stats";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a {@link
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.content.om.OverlayManager} for managing overlay packages.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @see android.content.om.OverlayManager
      * @hide
      */
     public static final String OVERLAY_SERVICE = "overlay";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link VrManager} for accessing the VR service.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      * @hide
      */
     @SystemApi
     public static final String VR_SERVICE = "vrmanager";
 
     /**
-     * Use with {@link #getSystemService} to retrieve an
+     * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.app.timezone.ITimeZoneRulesManager}.
      * @hide
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String TIME_ZONE_RULES_MANAGER_SERVICE = "timezone";
 
     /**
-     * Use with {@link #getSystemService} to retrieve a
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.content.pm.crossprofile.CrossProfileApps} for cross profile operations.
      *
-     * @see #getSystemService
+     * @see #getSystemService(String)
      */
     public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
 
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index e319750..cce6b84 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -652,4 +652,8 @@
     String getInstantAppAndroidId(String packageName, int userId);
 
     IArtManager getArtManager();
+
+    void setHarmfulAppWarning(String packageName, CharSequence warning, int userId);
+
+    CharSequence getHarmfulAppWarning(String packageName, int userId);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6cd4285..deb8dfb 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -787,7 +787,8 @@
 
     /**
      * Flag parameter for {@link #installPackage} to indicate that this package is an
-     * upgrade to a package that refers to the SDK via release letter.
+     * upgrade to a package that refers to the SDK via release letter or is targeting an SDK via
+     * release letter that the current build does not support.
      *
      * @hide
      */
@@ -5862,4 +5863,37 @@
     public @NonNull ArtManager getArtManager() {
         throw new UnsupportedOperationException("getArtManager not implemented in subclass");
     }
+
+    /**
+     * Sets or clears the harmful app warning details for the given app.
+     *
+     * When set, any attempt to launch an activity in this package will be intercepted and a
+     * warning dialog will be shown to the user instead, with the given warning. The user
+     * will have the option to proceed with the activity launch, or to uninstall the application.
+     *
+     * @param packageName The full name of the package to warn on.
+     * @param warning A warning string to display to the user describing the threat posed by the
+     *                application, or null to clear the warning.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SET_HARMFUL_APP_WARNINGS)
+    @SystemApi
+    public void setHarmfulAppWarning(@NonNull String packageName, @Nullable CharSequence warning) {
+        throw new UnsupportedOperationException("setHarmfulAppWarning not implemented in subclass");
+    }
+
+    /**
+     * Returns the harmful app warning string for the given app, or null if there is none set.
+     *
+     * @param packageName The full name of the desired package.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SET_HARMFUL_APP_WARNINGS)
+    @Nullable
+    @SystemApi
+    public CharSequence getHarmfulAppWarning(@NonNull String packageName) {
+        throw new UnsupportedOperationException("getHarmfulAppWarning not implemented in subclass");
+    }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 77eb57f2..6d6c02a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -35,7 +35,6 @@
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
 import static android.os.Build.VERSION_CODES.O;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
@@ -85,7 +84,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TypedValue;
-import android.util.apk.ApkSignatureSchemeV2Verifier;
 import android.util.apk.ApkSignatureVerifier;
 import android.view.Gravity;
 
@@ -112,8 +110,7 @@
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
 import java.security.spec.EncodedKeySpec;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
@@ -158,10 +155,6 @@
     private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
             SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
 
-    public static final int APK_SIGNING_UNKNOWN = 0;
-    public static final int APK_SIGNING_V1 = 1;
-    public static final int APK_SIGNING_V2 = 2;
-
     private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
 
     // TODO: switch outError users to PackageParserException
@@ -477,8 +470,7 @@
         public final int revisionCode;
         public final int installLocation;
         public final VerifierInfo[] verifiers;
-        public final Signature[] signatures;
-        public final Certificate[][] certificates;
+        public final SigningDetails signingDetails;
         public final boolean coreApp;
         public final boolean debuggable;
         public final boolean multiArch;
@@ -486,10 +478,11 @@
         public final boolean extractNativeLibs;
         public final boolean isolatedSplits;
 
-        public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
+        public ApkLite(String codePath, String packageName, String splitName,
+                boolean isFeatureSplit,
                 String configForSplit, String usesSplitName, int versionCode, int versionCodeMajor,
                 int revisionCode, int installLocation, List<VerifierInfo> verifiers,
-                Signature[] signatures, Certificate[][] certificates, boolean coreApp,
+                SigningDetails signingDetails, boolean coreApp,
                 boolean debuggable, boolean multiArch, boolean use32bitAbi,
                 boolean extractNativeLibs, boolean isolatedSplits) {
             this.codePath = codePath;
@@ -502,9 +495,8 @@
             this.versionCodeMajor = versionCodeMajor;
             this.revisionCode = revisionCode;
             this.installLocation = installLocation;
+            this.signingDetails = signingDetails;
             this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
-            this.signatures = signatures;
-            this.certificates = certificates;
             this.coreApp = coreApp;
             this.debuggable = debuggable;
             this.multiArch = multiArch;
@@ -807,10 +799,10 @@
             }
         }
         if ((flags&PackageManager.GET_SIGNATURES) != 0) {
-           int N = (p.mSignatures != null) ? p.mSignatures.length : 0;
-           if (N > 0) {
-                pi.signatures = new Signature[N];
-                System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
+            if (p.mSigningDetails.hasSignatures()) {
+                int numberOfSigs = p.mSigningDetails.signatures.length;
+                pi.signatures = new Signature[numberOfSigs];
+                System.arraycopy(p.mSigningDetails.signatures, 0, pi.signatures, 0, numberOfSigs);
             }
         }
         return pi;
@@ -818,15 +810,14 @@
 
     public static final int PARSE_MUST_BE_APK = 1 << 0;
     public static final int PARSE_IGNORE_PROCESSES = 1 << 1;
+    /** @deprecated forward lock no longer functional. remove. */
+    @Deprecated
     public static final int PARSE_FORWARD_LOCK = 1 << 2;
     public static final int PARSE_EXTERNAL_STORAGE = 1 << 3;
     public static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
     public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
     public static final int PARSE_ENFORCE_CODE = 1 << 6;
     public static final int PARSE_FORCE_SDK = 1 << 7;
-    /** @deprecated remove when fixing b/68860689 */
-    @Deprecated
-    public static final int PARSE_IS_EPHEMERAL = 1 << 8;
     public static final int PARSE_CHATTY = 1 << 31;
 
     @IntDef(flag = true, prefix = { "PARSE_" }, value = {
@@ -837,7 +828,6 @@
             PARSE_FORCE_SDK,
             PARSE_FORWARD_LOCK,
             PARSE_IGNORE_PROCESSES,
-            PARSE_IS_EPHEMERAL,
             PARSE_IS_SYSTEM_DIR,
             PARSE_MUST_BE_APK,
     })
@@ -1349,7 +1339,7 @@
             pkg.setVolumeUuid(volumeUuid);
             pkg.setApplicationVolumeUuid(volumeUuid);
             pkg.setBaseCodePath(apkPath);
-            pkg.setSignatures(null);
+            pkg.setSigningDetails(SigningDetails.UNKNOWN);
 
             return pkg;
 
@@ -1469,57 +1459,19 @@
         return pkg;
     }
 
-    public static int getApkSigningVersion(Package pkg) {
-        try {
-            if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
-                return APK_SIGNING_V2;
-            }
-            return APK_SIGNING_V1;
-        } catch (IOException e) {
+    /** Parses the public keys from the set of signatures. */
+    public static ArraySet<PublicKey> toSigningKeys(Signature[] signatures)
+            throws CertificateException {
+        ArraySet<PublicKey> keys = new ArraySet<>(signatures.length);
+        for (int i = 0; i < signatures.length; i++) {
+            keys.add(signatures[i].getPublicKey());
         }
-        return APK_SIGNING_UNKNOWN;
-    }
-
-    /**
-     * Populates the correct packages fields with the given certificates.
-     * <p>
-     * This is useful when we've already processed the certificates [such as during package
-     * installation through an installer session]. We don't re-process the archive and
-     * simply populate the correct fields.
-     */
-    public static void populateCertificates(Package pkg, Certificate[][] certificates)
-            throws PackageParserException {
-        pkg.mCertificates = null;
-        pkg.mSignatures = null;
-        pkg.mSigningKeys = null;
-
-        pkg.mCertificates = certificates;
-        try {
-            pkg.mSignatures = ApkSignatureVerifier.convertToSignatures(certificates);
-        } catch (CertificateEncodingException e) {
-            // certificates weren't encoded properly; something went wrong
-            throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
-                    "Failed to collect certificates from " + pkg.baseCodePath, e);
-        }
-        pkg.mSigningKeys = new ArraySet<>(certificates.length);
-        for (int i = 0; i < certificates.length; i++) {
-            Certificate[] signerCerts = certificates[i];
-            Certificate signerCert = signerCerts[0];
-            pkg.mSigningKeys.add(signerCert.getPublicKey());
-        }
-        // add signatures to child packages
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            Package childPkg = pkg.childPackages.get(i);
-            childPkg.mCertificates = pkg.mCertificates;
-            childPkg.mSignatures = pkg.mSignatures;
-            childPkg.mSigningKeys = pkg.mSigningKeys;
-        }
+        return keys;
     }
 
     /**
      * Collect certificates from all the APKs described in the given package,
-     * populating {@link Package#mSignatures}. Also asserts that all APK
+     * populating {@link Package#mSigningDetails}. Also asserts that all APK
      * contents are signed correctly and consistently.
      */
     public static void collectCertificates(Package pkg, @ParseFlags int parseFlags)
@@ -1528,17 +1480,13 @@
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
             Package childPkg = pkg.childPackages.get(i);
-            childPkg.mCertificates = pkg.mCertificates;
-            childPkg.mSignatures = pkg.mSignatures;
-            childPkg.mSigningKeys = pkg.mSigningKeys;
+            childPkg.mSigningDetails = pkg.mSigningDetails;
         }
     }
 
     private static void collectCertificatesInternal(Package pkg, @ParseFlags int parseFlags)
             throws PackageParserException {
-        pkg.mCertificates = null;
-        pkg.mSignatures = null;
-        pkg.mSigningKeys = null;
+        pkg.mSigningDetails = SigningDetails.UNKNOWN;
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
         try {
@@ -1558,12 +1506,12 @@
             throws PackageParserException {
         final String apkPath = apkFile.getAbsolutePath();
 
-        int minSignatureScheme = ApkSignatureVerifier.VERSION_JAR_SIGNATURE_SCHEME;
+        int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR;
         if (pkg.applicationInfo.isStaticSharedLibrary()) {
             // must use v2 signing scheme
-            minSignatureScheme = ApkSignatureVerifier.VERSION_APK_SIGNATURE_SCHEME_V2;
+            minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
         }
-        ApkSignatureVerifier.Result verified;
+        SigningDetails verified;
         if ((parseFlags & PARSE_IS_SYSTEM_DIR) != 0) {
             // systemDir APKs are already trusted, save time by not verifying
             verified = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
@@ -1571,29 +1519,14 @@
         } else {
             verified = ApkSignatureVerifier.verify(apkPath, minSignatureScheme);
         }
-        if (verified.signatureSchemeVersion
-                < ApkSignatureVerifier.VERSION_APK_SIGNATURE_SCHEME_V2) {
-            // TODO (b/68860689): move this logic to packagemanagerserivce
-            if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
-                    "No APK Signature Scheme v2 signature in ephemeral package " + apkPath);
-            }
-        }
 
         // Verify that entries are signed consistently with the first pkg
         // we encountered. Note that for splits, certificates may have
         // already been populated during an earlier parse of a base APK.
-        if (pkg.mCertificates == null) {
-            pkg.mCertificates = verified.certs;
-            pkg.mSignatures = verified.sigs;
-            pkg.mSigningKeys = new ArraySet<>(verified.certs.length);
-            for (int i = 0; i < verified.certs.length; i++) {
-                Certificate[] signerCerts = verified.certs[i];
-                Certificate signerCert = signerCerts[0];
-                pkg.mSigningKeys.add(signerCert.getPublicKey());
-            }
+        if (pkg.mSigningDetails == SigningDetails.UNKNOWN) {
+            pkg.mSigningDetails = verified;
         } else {
-            if (!Signature.areExactMatch(pkg.mSignatures, verified.sigs)) {
+            if (!Signature.areExactMatch(pkg.mSigningDetails.signatures, verified.signatures)) {
                 throw new PackageParserException(
                         INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
                         apkPath + " has mismatched certificates");
@@ -1655,8 +1588,7 @@
 
             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
 
-            final Signature[] signatures;
-            final Certificate[][] certificates;
+            final SigningDetails signingDetails;
             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
                 // TODO: factor signature related items out of Package object
                 final Package tempPkg = new Package((String) null);
@@ -1666,15 +1598,13 @@
                 } finally {
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
-                signatures = tempPkg.mSignatures;
-                certificates = tempPkg.mCertificates;
+                signingDetails = tempPkg.mSigningDetails;
             } else {
-                signatures = null;
-                certificates = null;
+                signingDetails = SigningDetails.UNKNOWN;
             }
 
             final AttributeSet attrs = parser;
-            return parseApkLite(apkPath, parser, attrs, signatures, certificates);
+            return parseApkLite(apkPath, parser, attrs, signingDetails);
 
         } catch (XmlPullParserException | IOException | RuntimeException e) {
             Slog.w(TAG, "Failed to parse " + apkPath, e);
@@ -1761,7 +1691,7 @@
     }
 
     private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
-            Signature[] signatures, Certificate[][] certificates)
+            SigningDetails signingDetails)
             throws IOException, XmlPullParserException, PackageParserException {
         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
 
@@ -1854,7 +1784,7 @@
 
         return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                 configForSplit, usesSplitName, versionCode, versionCodeMajor, revisionCode,
-                installLocation, verifiers, signatures, certificates, coreApp, debuggable,
+                installLocation, verifiers, signingDetails, coreApp, debuggable,
                 multiArch, use32bitAbi, extractNativeLibs, isolatedSplits);
     }
 
@@ -2039,11 +1969,6 @@
         String str = sa.getNonConfigurationString(
                 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
         if (str != null && str.length() > 0) {
-            if ((flags & PARSE_IS_EPHEMERAL) != 0) {
-                outError[0] = "sharedUserId not allowed in ephemeral application";
-                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
-                return null;
-            }
             String nameError = validateName(str, true, false);
             if (nameError != null && !"android".equals(pkg.packageName)) {
                 outError[0] = "<manifest> specifies bad sharedUserId name \""
@@ -2304,8 +2229,9 @@
                         return null;
                     }
 
+                    boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0;
                     final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
-                            targetCode, SDK_VERSION, SDK_CODENAMES, outError);
+                            targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch);
                     if (targetSdkVersion < 0) {
                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
                         return null;
@@ -2621,19 +2547,19 @@
      *                   application manifest, or 0 otherwise
      * @param targetCode targetSdkVersion code, if specified in the application
      *                   manifest, or {@code null} otherwise
-     * @param platformSdkVersion platform SDK version number, typically
-     *                           Build.VERSION.SDK_INT
      * @param platformSdkCodenames array of allowed pre-release SDK codenames
      *                             for this platform
      * @param outError output array to populate with error, if applicable
+     * @param forceCurrentDev if development target code is not available, use the current
+     *                        development version by default.
      * @return the targetSdkVersion to use at runtime, or -1 if the package is
      *         not compatible with this platform
      * @hide Exposed for unit testing only.
      */
     @TestApi
     public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
-            @Nullable String targetCode, @IntRange(from = 1) int platformSdkVersion,
-            @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
+            @Nullable String targetCode, @NonNull String[] platformSdkCodenames,
+            @NonNull String[] outError, boolean forceCurrentDev) {
         // If it's a release SDK, return the version number unmodified.
         if (targetCode == null) {
             return targetVers;
@@ -2641,7 +2567,7 @@
 
         // If it's a pre-release SDK and the codename matches this platform, it
         // definitely targets this SDK.
-        if (ArrayUtils.contains(platformSdkCodenames, targetCode)) {
+        if (ArrayUtils.contains(platformSdkCodenames, targetCode) || forceCurrentDev) {
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
@@ -5734,6 +5660,117 @@
         return true;
     }
 
+    /** A container for signing-related data of an application package. */
+    public static final class SigningDetails implements Parcelable {
+
+        @IntDef({SigningDetails.SignatureSchemeVersion.UNKNOWN,
+                SigningDetails.SignatureSchemeVersion.JAR,
+                SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2,
+                SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3})
+        public @interface SignatureSchemeVersion {
+            int UNKNOWN = 0;
+            int JAR = 1;
+            int SIGNING_BLOCK_V2 = 2;
+            int SIGNING_BLOCK_V3 = 3;
+        }
+
+        @Nullable
+        public final Signature[] signatures;
+        @SignatureSchemeVersion
+        public final int signatureSchemeVersion;
+        @Nullable
+        public final ArraySet<PublicKey> publicKeys;
+
+        /** A representation of unknown signing details. Use instead of null. */
+        public static final SigningDetails UNKNOWN =
+                new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null);
+
+        @VisibleForTesting
+        public SigningDetails(Signature[] signatures,
+                @SignatureSchemeVersion int signatureSchemeVersion,
+                ArraySet<PublicKey> keys) {
+            this.signatures = signatures;
+            this.signatureSchemeVersion = signatureSchemeVersion;
+            this.publicKeys = keys;
+        }
+
+        public SigningDetails(Signature[] signatures,
+                @SignatureSchemeVersion int signatureSchemeVersion)
+                throws CertificateException {
+            this(signatures, signatureSchemeVersion, toSigningKeys(signatures));
+        }
+
+        /** Returns true if the signing details have one or more signatures. */
+        public boolean hasSignatures() {
+            return signatures != null && signatures.length > 0;
+        }
+
+        /** Returns true if the signatures in this and other match exactly. */
+        public boolean signaturesMatchExactly(SigningDetails other) {
+            return Signature.areExactMatch(this.signatures, other.signatures);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            boolean isUnknown = UNKNOWN == this;
+            dest.writeBoolean(isUnknown);
+            if (isUnknown) {
+                return;
+            }
+            dest.writeTypedArray(this.signatures, flags);
+            dest.writeInt(this.signatureSchemeVersion);
+            dest.writeArraySet(this.publicKeys);
+        }
+
+        protected SigningDetails(Parcel in) {
+            final ClassLoader boot = Object.class.getClassLoader();
+            this.signatures = in.createTypedArray(Signature.CREATOR);
+            this.signatureSchemeVersion = in.readInt();
+            this.publicKeys = (ArraySet<PublicKey>) in.readArraySet(boot);
+        }
+
+        public static final Creator<SigningDetails> CREATOR = new Creator<SigningDetails>() {
+            @Override
+            public SigningDetails createFromParcel(Parcel source) {
+                if (source.readBoolean()) {
+                    return UNKNOWN;
+                }
+                return new SigningDetails(source);
+            }
+
+            @Override
+            public SigningDetails[] newArray(int size) {
+                return new SigningDetails[size];
+            }
+        };
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof SigningDetails)) return false;
+
+            SigningDetails that = (SigningDetails) o;
+
+            if (signatureSchemeVersion != that.signatureSchemeVersion) return false;
+            if (!Signature.areExactMatch(signatures, that.signatures)) return false;
+            return publicKeys != null ? publicKeys.equals(that.publicKeys)
+                    : that.publicKeys == null;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = +Arrays.hashCode(signatures);
+            result = 31 * result + signatureSchemeVersion;
+            result = 31 * result + (publicKeys != null ? publicKeys.hashCode() : 0);
+            return result;
+        }
+    }
+
     /**
      * Representation of a full package parsed from APK files on disk. A package
      * consists of a single base APK, and zero or more split APKs.
@@ -5840,8 +5877,7 @@
         public int mSharedUserLabel;
 
         // Signatures that were read from the package.
-        public Signature[] mSignatures;
-        public Certificate[][] mCertificates;
+        @NonNull public SigningDetails mSigningDetails = SigningDetails.UNKNOWN;
 
         // For use by package manager service for quick lookup of
         // preferred up order.
@@ -5893,7 +5929,6 @@
         /**
          * Data used to feed the KeySetManagerService
          */
-        public ArraySet<PublicKey> mSigningKeys;
         public ArraySet<String> mUpgradeKeySets;
         public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
 
@@ -5950,6 +5985,8 @@
             }
         }
 
+        /** @deprecated Forward locked apps no longer supported. Resource path not needed. */
+        @Deprecated
         public void setApplicationInfoResourcePath(String resourcePath) {
             this.applicationInfo.setResourcePath(resourcePath);
             if (childPackages != null) {
@@ -5960,6 +5997,8 @@
             }
         }
 
+        /** @deprecated Forward locked apps no longer supported. Resource path not needed. */
+        @Deprecated
         public void setApplicationInfoBaseResourcePath(String resourcePath) {
             this.applicationInfo.setBaseResourcePath(resourcePath);
             if (childPackages != null) {
@@ -6008,6 +6047,8 @@
             // Children have no splits
         }
 
+        /** @deprecated Forward locked apps no longer supported. Resource path not needed. */
+        @Deprecated
         public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) {
             this.applicationInfo.setSplitResourcePaths(resroucePaths);
             // Children have no splits
@@ -6037,12 +6078,13 @@
             }
         }
 
-        public void setSignatures(Signature[] signatures) {
-            this.mSignatures = signatures;
+        /** Sets signing details on the package and any of its children. */
+        public void setSigningDetails(@NonNull SigningDetails signingDetails) {
+            mSigningDetails = signingDetails;
             if (childPackages != null) {
                 final int packageCount = childPackages.size();
                 for (int i = 0; i < packageCount; i++) {
-                    childPackages.get(i).mSignatures = signatures;
+                    childPackages.get(i).mSigningDetails = signingDetails;
                 }
             }
         }
@@ -6243,6 +6285,31 @@
                 + " " + packageName + "}";
         }
 
+        public String dumpState_temp() {
+            String flags = "";
+            flags += ((applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ? "U" : "");
+            flags += ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? "S" : "");
+            if ("".equals(flags)) {
+                flags = "-";
+            }
+            String privFlags = "";
+            privFlags += ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0 ? "P" : "");
+            privFlags += ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0 ? "O" : "");
+            privFlags += ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0 ? "V" : "");
+            if ("".equals(privFlags)) {
+                privFlags = "-";
+            }
+            return "Package{"
+            + Integer.toHexString(System.identityHashCode(this))
+            + " " + packageName
+            + ", ver:" + getLongVersionCode()
+            + ", path: " + codePath
+            + ", flags: " + flags
+            + ", privFlags: " + privFlags
+            + ", extra: " + (mExtras == null ? "<<NULL>>" : Integer.toHexString(System.identityHashCode(mExtras)) + "}")
+            + "}";
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -6348,8 +6415,7 @@
             }
             mSharedUserLabel = dest.readInt();
 
-            mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class);
-            mCertificates = (Certificate[][]) dest.readSerializable();
+            mSigningDetails = dest.readParcelable(boot);
 
             mPreferredOrder = dest.readInt();
 
@@ -6389,7 +6455,6 @@
             mTrustedOverlay = (dest.readInt() == 1);
             mCompileSdkVersion = dest.readInt();
             mCompileSdkVersionCodename = dest.readString();
-            mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot);
             mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
 
             mKeySetMapping = readKeySetMapping(dest);
@@ -6489,8 +6554,7 @@
             dest.writeString(mSharedUserId);
             dest.writeInt(mSharedUserLabel);
 
-            dest.writeParcelableArray(mSignatures, flags);
-            dest.writeSerializable(mCertificates);
+            dest.writeParcelable(mSigningDetails, flags);
 
             dest.writeInt(mPreferredOrder);
 
@@ -6515,7 +6579,6 @@
             dest.writeInt(mTrustedOverlay ? 1 : 0);
             dest.writeInt(mCompileSdkVersion);
             dest.writeString(mCompileSdkVersionCodename);
-            dest.writeArraySet(mSigningKeys);
             dest.writeArraySet(mUpgradeKeySets);
             writeKeySetMapping(dest, mKeySetMapping);
             dest.writeString(cpuAbiOverride);
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 069b2d4..293beb2 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -52,6 +52,7 @@
     public int appLinkGeneration;
     public int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
     public int installReason;
+    public String harmfulAppWarning;
 
     public ArraySet<String> disabledComponents;
     public ArraySet<String> enabledComponents;
@@ -87,6 +88,7 @@
         enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
         overlayPaths =
             o.overlayPaths == null ? null : Arrays.copyOf(o.overlayPaths, o.overlayPaths.length);
+        harmfulAppWarning = o.harmfulAppWarning;
     }
 
     /**
@@ -247,6 +249,11 @@
                 }
             }
         }
+        if (harmfulAppWarning == null && oldState.harmfulAppWarning != null
+                || (harmfulAppWarning != null
+                        && !harmfulAppWarning.equals(oldState.harmfulAppWarning))) {
+            return false;
+        }
         return true;
     }
 }
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 3239212..97cb78b 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -815,7 +815,7 @@
             } finally {
                 stack.pop();
             }
-        } catch (Exception e) {
+        } catch (Exception | StackOverflowError e) {
             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
             final NotFoundException rnf = new NotFoundException(
                     "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
index 0a08353..2301824 100644
--- a/core/java/android/hardware/display/BrightnessChangeEvent.java
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -16,6 +16,8 @@
 
 package android.hardware.display;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -23,51 +25,65 @@
  * Data about a brightness settings change.
  *
  * {@see DisplayManager.getBrightnessEvents()}
- * TODO make this SystemAPI
  * @hide
  */
+@SystemApi
+@TestApi
 public final class BrightnessChangeEvent implements Parcelable {
     /** Brightness in nits */
-    public float brightness;
+    public final float brightness;
 
     /** Timestamp of the change {@see System.currentTimeMillis()} */
-    public long timeStamp;
+    public final long timeStamp;
 
     /** Package name of focused activity when brightness was changed.
      *  This will be null if the caller of {@see DisplayManager.getBrightnessEvents()}
      *  does not have access to usage stats {@see UsageStatsManager} */
-    public String packageName;
+    public final String packageName;
 
     /** User id of of the user running when brightness was changed.
      * @hide */
-    public int userId;
+    public final int userId;
 
     /** Lux values of recent sensor data */
-    public float[] luxValues;
+    public final float[] luxValues;
 
     /** Timestamps of the lux sensor readings {@see System.currentTimeMillis()} */
-    public long[] luxTimestamps;
+    public final long[] luxTimestamps;
 
     /** Most recent battery level when brightness was changed or Float.NaN */
-    public float batteryLevel;
+    public final float batteryLevel;
 
     /** Color filter active to provide night mode */
-    public boolean nightMode;
+    public final boolean nightMode;
 
     /** If night mode color filter is active this will be the temperature in kelvin */
-    public int colorTemperature;
+    public final int colorTemperature;
 
-    /** Brightness level before slider adjustment */
-    public float lastBrightness;
+    /** Brightness le vel before slider adjustment */
+    public final float lastBrightness;
 
-    public BrightnessChangeEvent() {
+    /** @hide */
+    private BrightnessChangeEvent(float brightness, long timeStamp, String packageName,
+            int userId, float[] luxValues, long[] luxTimestamps, float batteryLevel,
+            boolean nightMode, int colorTemperature, float lastBrightness) {
+        this.brightness = brightness;
+        this.timeStamp = timeStamp;
+        this.packageName = packageName;
+        this.userId = userId;
+        this.luxValues = luxValues;
+        this.luxTimestamps = luxTimestamps;
+        this.batteryLevel = batteryLevel;
+        this.nightMode = nightMode;
+        this.colorTemperature = colorTemperature;
+        this.lastBrightness = lastBrightness;
     }
 
     /** @hide */
-    public BrightnessChangeEvent(BrightnessChangeEvent other) {
+    public BrightnessChangeEvent(BrightnessChangeEvent other, boolean redactPackage) {
         this.brightness = other.brightness;
         this.timeStamp = other.timeStamp;
-        this.packageName = other.packageName;
+        this.packageName = redactPackage ? null : other.packageName;
         this.userId = other.userId;
         this.luxValues = other.luxValues;
         this.luxTimestamps = other.luxTimestamps;
@@ -118,4 +134,85 @@
         dest.writeInt(colorTemperature);
         dest.writeFloat(lastBrightness);
     }
+
+    /** @hide */
+    public static class Builder {
+        private float mBrightness;
+        private long mTimeStamp;
+        private String mPackageName;
+        private int mUserId;
+        private float[] mLuxValues;
+        private long[] mLuxTimestamps;
+        private float mBatteryLevel;
+        private boolean mNightMode;
+        private int mColorTemperature;
+        private float mLastBrightness;
+
+        /** {@see BrightnessChangeEvent#brightness} */
+        public Builder setBrightness(float brightness) {
+            mBrightness = brightness;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#timeStamp} */
+        public Builder setTimeStamp(long timeStamp) {
+            mTimeStamp = timeStamp;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#packageName} */
+        public Builder setPackageName(String packageName) {
+            mPackageName = packageName;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#userId} */
+        public Builder setUserId(int userId) {
+            mUserId = userId;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#luxValues} */
+        public Builder setLuxValues(float[] luxValues) {
+            mLuxValues = luxValues;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#luxTimestamps} */
+        public Builder setLuxTimestamps(long[] luxTimestamps) {
+            mLuxTimestamps = luxTimestamps;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#batteryLevel} */
+        public Builder setBatteryLevel(float batteryLevel) {
+            mBatteryLevel = batteryLevel;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#nightMode} */
+        public Builder setNightMode(boolean nightMode) {
+            mNightMode = nightMode;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#colorTemperature} */
+        public Builder setColorTemperature(int colorTemperature) {
+            mColorTemperature = colorTemperature;
+            return this;
+        }
+
+        /** {@see BrightnessChangeEvent#lastBrightness} */
+        public Builder setLastBrightness(float lastBrightness) {
+            mLastBrightness = lastBrightness;
+            return this;
+        }
+
+        /** Builds a BrightnessChangeEvent */
+        public BrightnessChangeEvent build() {
+            return new BrightnessChangeEvent(mBrightness, mTimeStamp,
+                    mPackageName, mUserId, mLuxValues, mLuxTimestamps, mBatteryLevel,
+                    mNightMode, mColorTemperature, mLastBrightness);
+        }
+    }
 }
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 6c3be81..2156491 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -16,6 +16,8 @@
 
 package android.hardware.display;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Pair;
@@ -25,6 +27,8 @@
 import java.util.Arrays;
 
 /** @hide */
+@SystemApi
+@TestApi
 public final class BrightnessConfiguration implements Parcelable {
     private final float[] mLux;
     private final float[] mNits;
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 97e9b9c..76ab35d 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -22,6 +22,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.graphics.Point;
@@ -622,6 +623,8 @@
      * Fetch {@link BrightnessChangeEvent}s.
      * @hide until we make it a system api.
      */
+    @SystemApi
+    @TestApi
     @RequiresPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE)
     public List<BrightnessChangeEvent> getBrightnessEvents() {
         return mGlobal.getBrightnessEvents(mContext.getOpPackageName());
@@ -632,6 +635,9 @@
      *
      * @hide
      */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS)
     public void setBrightnessConfiguration(BrightnessConfiguration c) {
         setBrightnessConfigurationForUser(c, UserHandle.myUserId());
     }
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index ca38076..bf5e391 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -17,6 +17,7 @@
 package android.hardware.radio;
 
 import android.graphics.Bitmap;
+import android.hardware.radio.ProgramList;
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 
@@ -73,14 +74,8 @@
      */
     boolean startBackgroundScan();
 
-    /**
-     * @param vendorFilter Vendor-specific filter, must be Map<String, String>
-     * @return the list, or null if scan is in progress
-     * @throws IllegalArgumentException if invalid arguments are passed
-     * @throws IllegalStateException if the scan has not been started, client may
-     *         call startBackgroundScan to fix this.
-     */
-    List<RadioManager.ProgramInfo> getProgramList(in Map vendorFilter);
+    void startProgramListUpdates(in ProgramList.Filter filter);
+    void stopProgramListUpdates();
 
     boolean isConfigFlagSupported(int flag);
     boolean isConfigFlagSet(int flag);
diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl
index 775e25c..54af30f 100644
--- a/core/java/android/hardware/radio/ITunerCallback.aidl
+++ b/core/java/android/hardware/radio/ITunerCallback.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+import android.hardware.radio.ProgramList;
 import android.hardware.radio.RadioManager;
 import android.hardware.radio.RadioMetadata;
 
@@ -30,6 +31,7 @@
     void onBackgroundScanAvailabilityChange(boolean isAvailable);
     void onBackgroundScanComplete();
     void onProgramListChanged();
+    void onProgramListUpdated(in ProgramList.Chunk chunk);
 
     /**
      * @param parameters Vendor-specific key-value pairs, must be Map<String, String>
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/core/java/android/hardware/radio/ProgramList.aidl
similarity index 77%
copy from telephony/java/android/telephony/data/InterfaceAddress.aidl
copy to core/java/android/hardware/radio/ProgramList.aidl
index d750363..34b7f97 100644
--- a/telephony/java/android/telephony/data/InterfaceAddress.aidl
+++ b/core/java/android/hardware/radio/ProgramList.aidl
@@ -1,5 +1,5 @@
-/*
- * Copyright 2017 The Android Open Source Project
+/**
+ * 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.
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.hardware.radio;
 
-parcelable InterfaceAddress;
+/** @hide */
+parcelable ProgramList.Filter;
+
+/** @hide */
+parcelable ProgramList.Chunk;
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
new file mode 100644
index 0000000..b2aa9ba
--- /dev/null
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -0,0 +1,427 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ProgramList implements AutoCloseable {
+
+    private final Object mLock = new Object();
+    private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mPrograms =
+            new HashMap<>();
+
+    private final List<ListCallback> mListCallbacks = new ArrayList<>();
+    private final List<OnCompleteListener> mOnCompleteListeners = new ArrayList<>();
+    private OnCloseListener mOnCloseListener;
+    private boolean mIsClosed = false;
+    private boolean mIsComplete = false;
+
+    ProgramList() {}
+
+    /**
+     * Callback for list change operations.
+     */
+    public abstract static class ListCallback {
+        /**
+         * Called when item was modified or added to the list.
+         */
+        public void onItemChanged(@NonNull ProgramSelector.Identifier id) { }
+
+        /**
+         * Called when item was removed from the list.
+         */
+        public void onItemRemoved(@NonNull ProgramSelector.Identifier id) { }
+    }
+
+    /**
+     * Listener of list complete event.
+     */
+    public interface OnCompleteListener {
+        /**
+         * Called when the list turned complete (i.e. when the scan process
+         * came to an end).
+         */
+        void onComplete();
+    }
+
+    interface OnCloseListener {
+        void onClose();
+    }
+
+    /**
+     * Registers list change callback with executor.
+     */
+    public void registerListCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull ListCallback callback) {
+        registerListCallback(new ListCallback() {
+            public void onItemChanged(@NonNull ProgramSelector.Identifier id) {
+                executor.execute(() -> callback.onItemChanged(id));
+            }
+
+            public void onItemRemoved(@NonNull ProgramSelector.Identifier id) {
+                executor.execute(() -> callback.onItemRemoved(id));
+            }
+        });
+    }
+
+    /**
+     * Registers list change callback.
+     */
+    public void registerListCallback(@NonNull ListCallback callback) {
+        synchronized (mLock) {
+            if (mIsClosed) return;
+            mListCallbacks.add(Objects.requireNonNull(callback));
+        }
+    }
+
+    /**
+     * Unregisters list change callback.
+     */
+    public void unregisterListCallback(@NonNull ListCallback callback) {
+        synchronized (mLock) {
+            if (mIsClosed) return;
+            mListCallbacks.remove(Objects.requireNonNull(callback));
+        }
+    }
+
+    /**
+     * Adds list complete event listener with executor.
+     */
+    public void addOnCompleteListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull OnCompleteListener listener) {
+        addOnCompleteListener(() -> executor.execute(listener::onComplete));
+    }
+
+    /**
+     * Adds list complete event listener.
+     */
+    public void addOnCompleteListener(@NonNull OnCompleteListener listener) {
+        synchronized (mLock) {
+            if (mIsClosed) return;
+            mOnCompleteListeners.add(Objects.requireNonNull(listener));
+            if (mIsComplete) listener.onComplete();
+        }
+    }
+
+    /**
+     * Removes list complete event listener.
+     */
+    public void removeOnCompleteListener(@NonNull OnCompleteListener listener) {
+        synchronized (mLock) {
+            if (mIsClosed) return;
+            mOnCompleteListeners.remove(Objects.requireNonNull(listener));
+        }
+    }
+
+    void setOnCloseListener(@Nullable OnCloseListener listener) {
+        synchronized (mLock) {
+            if (mOnCloseListener != null) {
+                throw new IllegalStateException("Close callback is already set");
+            }
+            mOnCloseListener = listener;
+        }
+    }
+
+    /**
+     * Disables list updates and releases all resources.
+     */
+    public void close() {
+        synchronized (mLock) {
+            if (mIsClosed) return;
+            mIsClosed = true;
+            mPrograms.clear();
+            mListCallbacks.clear();
+            mOnCompleteListeners.clear();
+            if (mOnCloseListener != null) {
+                mOnCloseListener.onClose();
+                mOnCloseListener = null;
+            }
+        }
+    }
+
+    void apply(@NonNull Chunk chunk) {
+        synchronized (mLock) {
+            if (mIsClosed) return;
+
+            mIsComplete = false;
+
+            if (chunk.isPurge()) {
+                new HashSet<>(mPrograms.keySet()).stream().forEach(id -> removeLocked(id));
+            }
+
+            chunk.getRemoved().stream().forEach(id -> removeLocked(id));
+            chunk.getModified().stream().forEach(info -> putLocked(info));
+
+            if (chunk.isComplete()) {
+                mIsComplete = true;
+                mOnCompleteListeners.forEach(cb -> cb.onComplete());
+            }
+        }
+    }
+
+    private void putLocked(@NonNull RadioManager.ProgramInfo value) {
+        ProgramSelector.Identifier key = value.getSelector().getPrimaryId();
+        mPrograms.put(Objects.requireNonNull(key), value);
+        ProgramSelector.Identifier sel = value.getSelector().getPrimaryId();
+        mListCallbacks.forEach(cb -> cb.onItemChanged(sel));
+    }
+
+    private void removeLocked(@NonNull ProgramSelector.Identifier key) {
+        RadioManager.ProgramInfo removed = mPrograms.remove(Objects.requireNonNull(key));
+        if (removed == null) return;
+        ProgramSelector.Identifier sel = removed.getSelector().getPrimaryId();
+        mListCallbacks.forEach(cb -> cb.onItemRemoved(sel));
+    }
+
+    /**
+     * Converts the program list in its current shape to the static List<>.
+     *
+     * @return the new List<> object; it won't receive any further updates
+     */
+    public @NonNull List<RadioManager.ProgramInfo> toList() {
+        synchronized (mLock) {
+            return mPrograms.values().stream().collect(Collectors.toList());
+        }
+    }
+
+    /**
+     * Returns the program with a specified primary identifier.
+     *
+     * @param id primary identifier of a program to fetch
+     * @return the program info, or null if there is no such program on the list
+     */
+    public @Nullable RadioManager.ProgramInfo get(@NonNull ProgramSelector.Identifier id) {
+        synchronized (mLock) {
+            return mPrograms.get(Objects.requireNonNull(id));
+        }
+    }
+
+    /**
+     * Filter for the program list.
+     */
+    public static final class Filter implements Parcelable {
+        private final @NonNull Set<Integer> mIdentifierTypes;
+        private final @NonNull Set<ProgramSelector.Identifier> mIdentifiers;
+        private final boolean mIncludeCategories;
+        private final boolean mExcludeModifications;
+        private final @Nullable Map<String, String> mVendorFilter;
+
+        /**
+         * Constructor of program list filter.
+         *
+         * Arrays passed to this constructor become owned by this object, do not modify them later.
+         *
+         * @param identifierTypes see getIdentifierTypes()
+         * @param identifiers see getIdentifiers()
+         * @param includeCategories see areCategoriesIncluded()
+         * @param excludeModifications see areModificationsExcluded()
+         */
+        public Filter(@NonNull Set<Integer> identifierTypes,
+                @NonNull Set<ProgramSelector.Identifier> identifiers,
+                boolean includeCategories, boolean excludeModifications) {
+            mIdentifierTypes = Objects.requireNonNull(identifierTypes);
+            mIdentifiers = Objects.requireNonNull(identifiers);
+            mIncludeCategories = includeCategories;
+            mExcludeModifications = excludeModifications;
+            mVendorFilter = null;
+        }
+
+        /**
+         * @hide for framework use only
+         */
+        public Filter(@Nullable Map<String, String> vendorFilter) {
+            mIdentifierTypes = Collections.emptySet();
+            mIdentifiers = Collections.emptySet();
+            mIncludeCategories = false;
+            mExcludeModifications = false;
+            mVendorFilter = vendorFilter;
+        }
+
+        private Filter(@NonNull Parcel in) {
+            mIdentifierTypes = Utils.createIntSet(in);
+            mIdentifiers = Utils.createSet(in, ProgramSelector.Identifier.CREATOR);
+            mIncludeCategories = in.readByte() != 0;
+            mExcludeModifications = in.readByte() != 0;
+            mVendorFilter = Utils.readStringMap(in);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            Utils.writeIntSet(dest, mIdentifierTypes);
+            Utils.writeSet(dest, mIdentifiers);
+            dest.writeByte((byte) (mIncludeCategories ? 1 : 0));
+            dest.writeByte((byte) (mExcludeModifications ? 1 : 0));
+            Utils.writeStringMap(dest, mVendorFilter);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Parcelable.Creator<Filter> CREATOR = new Parcelable.Creator<Filter>() {
+            public Filter createFromParcel(Parcel in) {
+                return new Filter(in);
+            }
+
+            public Filter[] newArray(int size) {
+                return new Filter[size];
+            }
+        };
+
+        /**
+         * @hide for framework use only
+         */
+        public Map<String, String> getVendorFilter() {
+            return mVendorFilter;
+        }
+
+        /**
+         * Returns the list of identifier types that satisfy the filter.
+         *
+         * If the program list entry contains at least one identifier of the type
+         * listed, it satisfies this condition.
+         *
+         * Empty list means no filtering on identifier type.
+         *
+         * @return the list of accepted identifier types, must not be modified
+         */
+        public @NonNull Set<Integer> getIdentifierTypes() {
+            return mIdentifierTypes;
+        }
+
+        /**
+         * Returns the list of identifiers that satisfy the filter.
+         *
+         * If the program list entry contains at least one listed identifier,
+         * it satisfies this condition.
+         *
+         * Empty list means no filtering on identifier.
+         *
+         * @return the list of accepted identifiers, must not be modified
+         */
+        public @NonNull Set<ProgramSelector.Identifier> getIdentifiers() {
+            return mIdentifiers;
+        }
+
+        /**
+         * Checks, if non-tunable entries that define tree structure on the
+         * program list (i.e. DAB ensembles) should be included.
+         */
+        public boolean areCategoriesIncluded() {
+            return mIncludeCategories;
+        }
+
+        /**
+         * Checks, if updates on entry modifications should be disabled.
+         *
+         * If true, 'modified' vector of ProgramListChunk must contain list
+         * additions only. Once the program is added to the list, it's not
+         * updated anymore.
+         */
+        public boolean areModificationsExcluded() {
+            return mExcludeModifications;
+        }
+    }
+
+    /**
+     * @hide This is a transport class used for internal communication between
+     *       Broadcast Radio Service and RadioManager.
+     *       Do not use it directly.
+     */
+    public static final class Chunk implements Parcelable {
+        private final boolean mPurge;
+        private final boolean mComplete;
+        private final @NonNull Set<RadioManager.ProgramInfo> mModified;
+        private final @NonNull Set<ProgramSelector.Identifier> mRemoved;
+
+        public Chunk(boolean purge, boolean complete,
+                @Nullable Set<RadioManager.ProgramInfo> modified,
+                @Nullable Set<ProgramSelector.Identifier> removed) {
+            mPurge = purge;
+            mComplete = complete;
+            mModified = (modified != null) ? modified : Collections.emptySet();
+            mRemoved = (removed != null) ? removed : Collections.emptySet();
+        }
+
+        private Chunk(@NonNull Parcel in) {
+            mPurge = in.readByte() != 0;
+            mComplete = in.readByte() != 0;
+            mModified = Utils.createSet(in, RadioManager.ProgramInfo.CREATOR);
+            mRemoved = Utils.createSet(in, ProgramSelector.Identifier.CREATOR);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeByte((byte) (mPurge ? 1 : 0));
+            dest.writeByte((byte) (mComplete ? 1 : 0));
+            Utils.writeSet(dest, mModified);
+            Utils.writeSet(dest, mRemoved);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Parcelable.Creator<Chunk> CREATOR = new Parcelable.Creator<Chunk>() {
+            public Chunk createFromParcel(Parcel in) {
+                return new Chunk(in);
+            }
+
+            public Chunk[] newArray(int size) {
+                return new Chunk[size];
+            }
+        };
+
+        public boolean isPurge() {
+            return mPurge;
+        }
+
+        public boolean isComplete() {
+            return mComplete;
+        }
+
+        public @NonNull Set<RadioManager.ProgramInfo> getModified() {
+            return mModified;
+        }
+
+        public @NonNull Set<ProgramSelector.Identifier> getRemoved() {
+            return mRemoved;
+        }
+    }
+}
diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index 2211cee..3556751 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -59,6 +59,7 @@
  */
 @SystemApi
 public final class ProgramSelector implements Parcelable {
+    public static final int PROGRAM_TYPE_INVALID = 0;
     /** Analogue AM radio (with or without RDS). */
     public static final int PROGRAM_TYPE_AM = 1;
     /** analogue FM radio (with or without RDS). */
@@ -77,6 +78,7 @@
     public static final int PROGRAM_TYPE_VENDOR_START = 1000;
     public static final int PROGRAM_TYPE_VENDOR_END = 1999;
     @IntDef(prefix = { "PROGRAM_TYPE_" }, value = {
+        PROGRAM_TYPE_INVALID,
         PROGRAM_TYPE_AM,
         PROGRAM_TYPE_FM,
         PROGRAM_TYPE_AM_HD,
@@ -89,6 +91,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProgramType {}
 
+    public static final int IDENTIFIER_TYPE_INVALID = 0;
     /** kHz */
     public static final int IDENTIFIER_TYPE_AMFM_FREQUENCY = 1;
     /** 16bit */
@@ -148,6 +151,7 @@
     public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = PROGRAM_TYPE_VENDOR_START;
     public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = PROGRAM_TYPE_VENDOR_END;
     @IntDef(prefix = { "IDENTIFIER_TYPE_" }, value = {
+        IDENTIFIER_TYPE_INVALID,
         IDENTIFIER_TYPE_AMFM_FREQUENCY,
         IDENTIFIER_TYPE_RDS_PI,
         IDENTIFIER_TYPE_HD_STATION_ID_EXT,
@@ -268,7 +272,7 @@
      * Vendor identifiers are passed as-is to the HAL implementation,
      * preserving elements order.
      *
-     * @return a array of vendor identifiers, must not be modified.
+     * @return an array of vendor identifiers, must not be modified.
      */
     public @NonNull long[] getVendorIds() {
         return mVendorIds;
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index b740f14..56668ac 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -185,25 +185,6 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ConfigFlag {}
 
-    private static void writeStringMap(@NonNull Parcel dest, @NonNull Map<String, String> map) {
-        dest.writeInt(map.size());
-        for (Map.Entry<String, String> entry : map.entrySet()) {
-            dest.writeString(entry.getKey());
-            dest.writeString(entry.getValue());
-        }
-    }
-
-    private static @NonNull Map<String, String> readStringMap(@NonNull Parcel in) {
-        int size = in.readInt();
-        Map<String, String> map = new HashMap<>();
-        while (size-- > 0) {
-            String key = in.readString();
-            String value = in.readString();
-            map.put(key, value);
-        }
-        return map;
-    }
-
     /*****************************************************************************
      * Lists properties, options and radio bands supported by a given broadcast radio module.
      * Each module has a unique ID used to address it when calling RadioManager APIs.
@@ -415,7 +396,7 @@
             mIsBgScanSupported = in.readInt() == 1;
             mSupportedProgramTypes = arrayToSet(in.createIntArray());
             mSupportedIdentifierTypes = arrayToSet(in.createIntArray());
-            mVendorInfo = readStringMap(in);
+            mVendorInfo = Utils.readStringMap(in);
         }
 
         public static final Parcelable.Creator<ModuleProperties> CREATOR
@@ -445,7 +426,7 @@
             dest.writeInt(mIsBgScanSupported ? 1 : 0);
             dest.writeIntArray(setToArray(mSupportedProgramTypes));
             dest.writeIntArray(setToArray(mSupportedIdentifierTypes));
-            writeStringMap(dest, mVendorInfo);
+            Utils.writeStringMap(dest, mVendorInfo);
         }
 
         @Override
@@ -1410,7 +1391,7 @@
         private static final int FLAG_TRAFFIC_ANNOUNCEMENT = 1 << 3;
 
         @NonNull private final ProgramSelector mSelector;
-        private final boolean mTuned;
+        private final boolean mTuned;  // TODO(b/69958777): replace with mFlags
         private final boolean mStereo;
         private final boolean mDigital;
         private final int mFlags;
@@ -1418,7 +1399,8 @@
         private final RadioMetadata mMetadata;
         @NonNull private final Map<String, String> mVendorInfo;
 
-        ProgramInfo(@NonNull ProgramSelector selector, boolean tuned, boolean stereo,
+        /** @hide */
+        public ProgramInfo(@NonNull ProgramSelector selector, boolean tuned, boolean stereo,
                 boolean digital, int signalStrength, RadioMetadata metadata, int flags,
                 Map<String, String> vendorInfo) {
             mSelector = selector;
@@ -1564,7 +1546,7 @@
                 mMetadata = null;
             }
             mFlags = in.readInt();
-            mVendorInfo = readStringMap(in);
+            mVendorInfo = Utils.readStringMap(in);
         }
 
         public static final Parcelable.Creator<ProgramInfo> CREATOR
@@ -1592,7 +1574,7 @@
                 mMetadata.writeToParcel(dest, flags);
             }
             dest.writeInt(mFlags);
-            writeStringMap(dest, mVendorInfo);
+            Utils.writeStringMap(dest, mVendorInfo);
         }
 
         @Override
@@ -1727,7 +1709,8 @@
             Log.e(TAG, "Failed to open tuner");
             return null;
         }
-        return new TunerAdapter(tuner, config != null ? config.getType() : BAND_INVALID);
+        return new TunerAdapter(tuner, halCallback,
+                config != null ? config.getType() : BAND_INVALID);
     }
 
     @NonNull private final Context mContext;
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index 0d367e7..ed20c4a 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -280,11 +280,29 @@
      * @throws IllegalStateException if the scan is in progress or has not been started,
      *         startBackgroundScan() call may fix it.
      * @throws IllegalArgumentException if the vendorFilter argument is not valid.
+     * @deprecated Use {@link getDynamicProgramList} instead.
      */
+    @Deprecated
     public abstract @NonNull List<RadioManager.ProgramInfo>
             getProgramList(@Nullable Map<String, String> vendorFilter);
 
     /**
+     * Get the dynamic list of discovered radio stations.
+     *
+     * The list object is updated asynchronously; to get the updates register
+     * with {@link ProgramList#addListCallback}.
+     *
+     * When the returned object is no longer used, it must be closed.
+     *
+     * @param filter filter for the list, or null to get the full list.
+     * @return the dynamic program list object, close it after use
+     *         or {@code null} if program list is not supported by the tuner
+     */
+    public @Nullable ProgramList getDynamicProgramList(@Nullable ProgramList.Filter filter) {
+        return null;
+    }
+
+    /**
      * Checks, if the analog playback is forced, see setAnalogForced.
      *
      * @throws IllegalStateException if the switch is not supported at current
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index 8ad609d..91944bf 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -33,15 +33,18 @@
     private static final String TAG = "BroadcastRadio.TunerAdapter";
 
     @NonNull private final ITuner mTuner;
+    @NonNull private final TunerCallbackAdapter mCallback;
     private boolean mIsClosed = false;
 
     private @RadioManager.Band int mBand;
 
-    TunerAdapter(ITuner tuner, @RadioManager.Band int band) {
-        if (tuner == null) {
-            throw new NullPointerException();
-        }
-        mTuner = tuner;
+    private ProgramList mLegacyListProxy;
+    private Map<String, String> mLegacyListFilter;
+
+    TunerAdapter(@NonNull ITuner tuner, @NonNull TunerCallbackAdapter callback,
+            @RadioManager.Band int band) {
+        mTuner = Objects.requireNonNull(tuner);
+        mCallback = Objects.requireNonNull(callback);
         mBand = band;
     }
 
@@ -53,6 +56,10 @@
                 return;
             }
             mIsClosed = true;
+            if (mLegacyListProxy != null) {
+                mLegacyListProxy.close();
+                mLegacyListProxy = null;
+            }
         }
         try {
             mTuner.close();
@@ -227,10 +234,55 @@
     @Override
     public @NonNull List<RadioManager.ProgramInfo>
             getProgramList(@Nullable Map<String, String> vendorFilter) {
-        try {
-            return mTuner.getProgramList(vendorFilter);
-        } catch (RemoteException e) {
-            throw new RuntimeException("service died", e);
+        synchronized (mTuner) {
+            if (mLegacyListProxy == null || !Objects.equals(mLegacyListFilter, vendorFilter)) {
+                Log.i(TAG, "Program list filter has changed, requesting new list");
+                mLegacyListProxy = new ProgramList();
+                mLegacyListFilter = vendorFilter;
+
+                mCallback.clearLastCompleteList();
+                mCallback.setProgramListObserver(mLegacyListProxy, () -> { });
+                try {
+                    mTuner.startProgramListUpdates(new ProgramList.Filter(vendorFilter));
+                } catch (RemoteException ex) {
+                    throw new RuntimeException("service died", ex);
+                }
+            }
+
+            List<RadioManager.ProgramInfo> list = mCallback.getLastCompleteList();
+            if (list == null) throw new IllegalStateException("Program list is not ready yet");
+            return list;
+        }
+    }
+
+    @Override
+    public @Nullable ProgramList getDynamicProgramList(@Nullable ProgramList.Filter filter) {
+        synchronized (mTuner) {
+            if (mLegacyListProxy != null) {
+                mLegacyListProxy.close();
+                mLegacyListProxy = null;
+            }
+            mLegacyListFilter = null;
+
+            ProgramList list = new ProgramList();
+            mCallback.setProgramListObserver(list, () -> {
+                try {
+                    mTuner.stopProgramListUpdates();
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Couldn't stop program list updates", ex);
+                }
+            });
+
+            try {
+                mTuner.startProgramListUpdates(filter);
+            } catch (UnsupportedOperationException ex) {
+                return null;
+            } catch (RemoteException ex) {
+                mCallback.setProgramListObserver(null, () -> { });
+                throw new RuntimeException("service died", ex);
+            }
+
+            return list;
         }
     }
 
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index a01f658..b299ffe 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -22,7 +22,9 @@
 import android.os.Looper;
 import android.util.Log;
 
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Implements the ITunerCallback interface by forwarding calls to RadioTuner.Callback.
@@ -30,9 +32,14 @@
 class TunerCallbackAdapter extends ITunerCallback.Stub {
     private static final String TAG = "BroadcastRadio.TunerCallbackAdapter";
 
+    private final Object mLock = new Object();
     @NonNull private final RadioTuner.Callback mCallback;
     @NonNull private final Handler mHandler;
 
+    @Nullable ProgramList mProgramList;
+    @Nullable List<RadioManager.ProgramInfo> mLastCompleteList;  // for legacy getProgramList call
+    private boolean mDelayedCompleteCallback = false;
+
     TunerCallbackAdapter(@NonNull RadioTuner.Callback callback, @Nullable Handler handler) {
         mCallback = callback;
         if (handler == null) {
@@ -42,6 +49,49 @@
         }
     }
 
+    void setProgramListObserver(@Nullable ProgramList programList,
+            @NonNull ProgramList.OnCloseListener closeListener) {
+        Objects.requireNonNull(closeListener);
+        synchronized (mLock) {
+            if (mProgramList != null) {
+                Log.w(TAG, "Previous program list observer wasn't properly closed, closing it...");
+                mProgramList.close();
+            }
+            mProgramList = programList;
+            if (programList == null) return;
+            programList.setOnCloseListener(() -> {
+                synchronized (mLock) {
+                    if (mProgramList != programList) return;
+                    mProgramList = null;
+                    mLastCompleteList = null;
+                    closeListener.onClose();
+                }
+            });
+            programList.addOnCompleteListener(() -> {
+                synchronized (mLock) {
+                    if (mProgramList != programList) return;
+                    mLastCompleteList = programList.toList();
+                    if (mDelayedCompleteCallback) {
+                        Log.d(TAG, "Sending delayed onBackgroundScanComplete callback");
+                        sendBackgroundScanCompleteLocked();
+                    }
+                }
+            });
+        }
+    }
+
+    @Nullable List<RadioManager.ProgramInfo> getLastCompleteList() {
+        synchronized (mLock) {
+            return mLastCompleteList;
+        }
+    }
+
+    void clearLastCompleteList() {
+        synchronized (mLock) {
+            mLastCompleteList = null;
+        }
+    }
+
     @Override
     public void onError(int status) {
         mHandler.post(() -> mCallback.onError(status));
@@ -87,9 +137,22 @@
         mHandler.post(() -> mCallback.onBackgroundScanAvailabilityChange(isAvailable));
     }
 
+    private void sendBackgroundScanCompleteLocked() {
+        mDelayedCompleteCallback = false;
+        mHandler.post(() -> mCallback.onBackgroundScanComplete());
+    }
+
     @Override
     public void onBackgroundScanComplete() {
-        mHandler.post(() -> mCallback.onBackgroundScanComplete());
+        synchronized (mLock) {
+            if (mLastCompleteList == null) {
+                Log.i(TAG, "Got onBackgroundScanComplete callback, but the "
+                        + "program list didn't get through yet. Delaying it...");
+                mDelayedCompleteCallback = true;
+                return;
+            }
+            sendBackgroundScanCompleteLocked();
+        }
     }
 
     @Override
@@ -98,6 +161,14 @@
     }
 
     @Override
+    public void onProgramListUpdated(ProgramList.Chunk chunk) {
+        synchronized (mLock) {
+            if (mProgramList == null) return;
+            mProgramList.apply(Objects.requireNonNull(chunk));
+        }
+    }
+
+    @Override
     public void onParametersUpdated(Map parameters) {
         mHandler.post(() -> mCallback.onParametersUpdated(parameters));
     }
diff --git a/core/java/android/hardware/radio/Utils.java b/core/java/android/hardware/radio/Utils.java
new file mode 100644
index 0000000..09bf8fe
--- /dev/null
+++ b/core/java/android/hardware/radio/Utils.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+final class Utils {
+    static void writeStringMap(@NonNull Parcel dest, @Nullable Map<String, String> map) {
+        if (map == null) {
+            dest.writeInt(0);
+            return;
+        }
+        dest.writeInt(map.size());
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            dest.writeString(entry.getKey());
+            dest.writeString(entry.getValue());
+        }
+    }
+
+    static @NonNull Map<String, String> readStringMap(@NonNull Parcel in) {
+        int size = in.readInt();
+        Map<String, String> map = new HashMap<>();
+        while (size-- > 0) {
+            String key = in.readString();
+            String value = in.readString();
+            map.put(key, value);
+        }
+        return map;
+    }
+
+    static <T extends Parcelable> void writeSet(@NonNull Parcel dest, @Nullable Set<T> set) {
+        if (set == null) {
+            dest.writeInt(0);
+            return;
+        }
+        dest.writeInt(set.size());
+        set.stream().forEach(elem -> dest.writeTypedObject(elem, 0));
+    }
+
+    static <T> Set<T> createSet(@NonNull Parcel in, Parcelable.Creator<T> c) {
+        int size = in.readInt();
+        Set<T> set = new HashSet<>();
+        while (size-- > 0) {
+            set.add(in.readTypedObject(c));
+        }
+        return set;
+    }
+
+    static void writeIntSet(@NonNull Parcel dest, @Nullable Set<Integer> set) {
+        if (set == null) {
+            dest.writeInt(0);
+            return;
+        }
+        dest.writeInt(set.size());
+        set.stream().forEach(elem -> dest.writeInt(Objects.requireNonNull(elem)));
+    }
+
+    static Set<Integer> createIntSet(@NonNull Parcel in) {
+        return createSet(in, new Parcelable.Creator<Integer>() {
+            public Integer createFromParcel(Parcel in) {
+                return in.readInt();
+            }
+
+            public Integer[] newArray(int size) {
+                return new Integer[size];
+            }
+        });
+    }
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 02b1c65..7528bc3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -18,6 +18,7 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
@@ -339,42 +340,35 @@
     final Insets mTmpInsets = new Insets();
     final int[] mTmpLocation = new int[2];
 
-    final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
-            new ViewTreeObserver.OnComputeInternalInsetsListener() {
-        public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
-            if (isExtractViewShown()) {
-                // In true fullscreen mode, we just say the window isn't covering
-                // any content so we don't impact whatever is behind.
-                View decor = getWindow().getWindow().getDecorView();
-                info.contentInsets.top = info.visibleInsets.top
-                        = decor.getHeight();
-                info.touchableRegion.setEmpty();
-                info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
-            } else {
-                onComputeInsets(mTmpInsets);
-                info.contentInsets.top = mTmpInsets.contentTopInsets;
-                info.visibleInsets.top = mTmpInsets.visibleTopInsets;
-                info.touchableRegion.set(mTmpInsets.touchableRegion);
-                info.setTouchableInsets(mTmpInsets.touchableInsets);
+    final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
+        if (isExtractViewShown()) {
+            // In true fullscreen mode, we just say the window isn't covering
+            // any content so we don't impact whatever is behind.
+            View decor = getWindow().getWindow().getDecorView();
+            info.contentInsets.top = info.visibleInsets.top = decor.getHeight();
+            info.touchableRegion.setEmpty();
+            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+        } else {
+            onComputeInsets(mTmpInsets);
+            info.contentInsets.top = mTmpInsets.contentTopInsets;
+            info.visibleInsets.top = mTmpInsets.visibleTopInsets;
+            info.touchableRegion.set(mTmpInsets.touchableRegion);
+            info.setTouchableInsets(mTmpInsets.touchableInsets);
+        }
+    };
+
+    final View.OnClickListener mActionClickListener = v -> {
+        final EditorInfo ei = getCurrentInputEditorInfo();
+        final InputConnection ic = getCurrentInputConnection();
+        if (ei != null && ic != null) {
+            if (ei.actionId != 0) {
+                ic.performEditorAction(ei.actionId);
+            } else if ((ei.imeOptions & EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE) {
+                ic.performEditorAction(ei.imeOptions & EditorInfo.IME_MASK_ACTION);
             }
         }
     };
 
-    final View.OnClickListener mActionClickListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            final EditorInfo ei = getCurrentInputEditorInfo();
-            final InputConnection ic = getCurrentInputConnection();
-            if (ei != null && ic != null) {
-                if (ei.actionId != 0) {
-                    ic.performEditorAction(ei.actionId);
-                } else if ((ei.imeOptions&EditorInfo.IME_MASK_ACTION)
-                        != EditorInfo.IME_ACTION_NONE) {
-                    ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
-                }
-            }
-        }
-    };
-    
     /**
      * Concrete implementation of
      * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
@@ -852,6 +846,11 @@
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
+        // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
+        // by default (but IME developers can opt this out later if they want a new behavior).
+        mWindow.getWindow().setFlags(
+                FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+
         initViews();
         mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
     }
@@ -882,8 +881,6 @@
         mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
         mRootView = mInflater.inflate(
                 com.android.internal.R.layout.input_method, null);
-        mRootView.setSystemUiVisibility(
-                View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
         mWindow.setContentView(mRootView);
         mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
@@ -892,20 +889,20 @@
             mWindow.getWindow().setWindowAnimations(
                     com.android.internal.R.style.Animation_InputMethodFancy);
         }
-        mFullscreenArea = (ViewGroup)mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
+        mFullscreenArea = mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
         mExtractViewHidden = false;
-        mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea);
+        mExtractFrame = mRootView.findViewById(android.R.id.extractArea);
         mExtractView = null;
         mExtractEditText = null;
         mExtractAccessories = null;
         mExtractAction = null;
         mFullscreenApplied = false;
-        
-        mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea);
-        mInputFrame = (FrameLayout)mRootView.findViewById(android.R.id.inputArea);
+
+        mCandidatesFrame = mRootView.findViewById(android.R.id.candidatesArea);
+        mInputFrame = mRootView.findViewById(android.R.id.inputArea);
         mInputView = null;
         mIsInputViewShown = false;
-        
+
         mExtractFrame.setVisibility(View.GONE);
         mCandidatesVisibility = getCandidatesHiddenVisibility();
         mCandidatesFrame.setVisibility(mCandidatesVisibility);
@@ -1085,33 +1082,6 @@
     }
 
     /**
-     * Close/hide the input method's soft input area, so the user no longer
-     * sees it or can interact with it.  This can only be called
-     * from the currently active input method, as validated by the given token.
-     *
-     * @param flags Provides additional operating flags.  Currently may be
-     * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY},
-     * {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set.
-     */
-    public void hideSoftInputFromInputMethod(int flags) {
-        mImm.hideSoftInputFromInputMethodInternal(mToken, flags);
-    }
-
-    /**
-     * Show the input method's soft input area, so the user
-     * sees the input method window and can interact with it.
-     * This can only be called from the currently active input method,
-     * as validated by the given token.
-     *
-     * @param flags Provides additional operating flags.  Currently may be
-     * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT} or
-     * {@link InputMethodManager#SHOW_FORCED} bit set.
-     */
-    public void showSoftInputFromInputMethod(int flags) {
-        mImm.showSoftInputFromInputMethodInternal(mToken, flags);
-    }
-
-    /**
      * Force switch to the last used input method and subtype. If the last input method didn't have
      * any subtypes, the framework will simply switch to the last input method with no subtype
      * specified.
@@ -1457,17 +1427,17 @@
     public int getCandidatesHiddenVisibility() {
         return isExtractViewShown() ? View.GONE : View.INVISIBLE;
     }
-    
+
     public void showStatusIcon(@DrawableRes int iconResId) {
         mStatusIcon = iconResId;
-        mImm.showStatusIcon(mToken, getPackageName(), iconResId);
+        mImm.showStatusIconInternal(mToken, getPackageName(), iconResId);
     }
-    
+
     public void hideStatusIcon() {
         mStatusIcon = 0;
-        mImm.hideStatusIcon(mToken);
+        mImm.hideStatusIconInternal(mToken);
     }
-    
+
     /**
      * Force switch to a new input method, as identified by <var>id</var>.  This
      * input method will be destroyed, and the requested one started on the
@@ -1476,9 +1446,9 @@
      * @param id Unique identifier of the new input method ot start.
      */
     public void switchInputMethod(String id) {
-        mImm.setInputMethod(mToken, id);
+        mImm.setInputMethodInternal(mToken, id);
     }
-    
+
     public void setExtractView(View view) {
         mExtractFrame.removeAllViews();
         mExtractFrame.addView(view, new FrameLayout.LayoutParams(
@@ -1486,13 +1456,13 @@
                 ViewGroup.LayoutParams.MATCH_PARENT));
         mExtractView = view;
         if (view != null) {
-            mExtractEditText = (ExtractEditText)view.findViewById(
+            mExtractEditText = view.findViewById(
                     com.android.internal.R.id.inputExtractEditText);
             mExtractEditText.setIME(this);
             mExtractAction = view.findViewById(
                     com.android.internal.R.id.inputExtractAction);
             if (mExtractAction != null) {
-                mExtractAccessories = (ViewGroup)view.findViewById(
+                mExtractAccessories = view.findViewById(
                         com.android.internal.R.id.inputExtractAccessories);
             }
             startExtractingText(false);
@@ -1741,7 +1711,7 @@
             // Rethrow the exception to preserve the existing behavior.  Some IMEs may have directly
             // called this method and relied on this exception for some clean-up tasks.
             // TODO: Give developers a clear guideline of whether it's OK to call this method or
-            // InputMethodManager#showSoftInputFromInputMethod() should always be used instead.
+            // InputMethodService#requestShowSelf(int) should always be used instead.
             throw e;
         } finally {
             // TODO: Is it OK to set true when we get BadTokenException?
@@ -2063,27 +2033,30 @@
 
     /**
      * Close this input method's soft input area, removing it from the display.
-     * The input method will continue running, but the user can no longer use
-     * it to generate input by touching the screen.
-     * @param flags Provides additional operating flags.  Currently may be
-     * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY
-     * InputMethodManager.HIDE_IMPLICIT_ONLY} bit set.
+     *
+     * The input method will continue running, but the user can no longer use it to generate input
+     * by touching the screen.
+     *
+     * @see InputMethodManager#HIDE_IMPLICIT_ONLY
+     * @see InputMethodManager#HIDE_NOT_ALWAYS
+     * @param flags Provides additional operating flags.
      */
     public void requestHideSelf(int flags) {
-        mImm.hideSoftInputFromInputMethod(mToken, flags);
+        mImm.hideSoftInputFromInputMethodInternal(mToken, flags);
     }
-    
+
     /**
-     * Show the input method. This is a call back to the
-     * IMF to handle showing the input method.
-     * @param flags Provides additional operating flags.  Currently may be
-     * 0 or have the {@link InputMethodManager#SHOW_FORCED
-     * InputMethodManager.} bit set.
+     * Show the input method's soft input area, so the user sees the input method window and can
+     * interact with it.
+     *
+     * @see InputMethodManager#SHOW_IMPLICIT
+     * @see InputMethodManager#SHOW_FORCED
+     * @param flags Provides additional operating flags.
      */
-    private void requestShowSelf(int flags) {
-        mImm.showSoftInputFromInputMethod(mToken, flags);
+    public void requestShowSelf(int flags) {
+        mImm.showSoftInputFromInputMethodInternal(mToken, flags);
     }
-    
+
     private boolean handleBack(boolean doIt) {
         if (mShowInputRequested) {
             // If the soft input area is shown, back closes it and we
@@ -2750,7 +2723,7 @@
      * application.
      * This cannot be {@code null}.
      * @param inputConnection {@link InputConnection} with which
-     * {@link InputConnection#commitContent(InputContentInfo, Bundle)} will be called.
+     * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called.
      * @hide
      */
     @Override
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index d6992aa..287bdc8 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -60,7 +61,7 @@
     })
     public @interface MacAddressType { }
 
-    /** Indicates a MAC address of unknown type. */
+    /** @hide Indicates a MAC address of unknown type. */
     public static final int TYPE_UNKNOWN = 0;
     /** Indicates a MAC address is a unicast address. */
     public static final int TYPE_UNICAST = 1;
@@ -92,7 +93,7 @@
      *
      * @return the int constant representing the MAC address type of this MacAddress.
      */
-    public @MacAddressType int addressType() {
+    public @MacAddressType int getAddressType() {
         if (equals(BROADCAST_ADDRESS)) {
             return TYPE_BROADCAST;
         }
@@ -120,12 +121,12 @@
     /**
      * @return a byte array representation of this MacAddress.
      */
-    public byte[] toByteArray() {
+    public @NonNull byte[] toByteArray() {
         return byteAddrFromLongAddr(mAddr);
     }
 
     @Override
-    public String toString() {
+    public @NonNull String toString() {
         return stringAddrFromLongAddr(mAddr);
     }
 
@@ -133,7 +134,7 @@
      * @return a String representation of the OUI part of this MacAddress made of 3 hexadecimal
      * numbers in [0,ff] joined by ':' characters.
      */
-    public String toOuiString() {
+    public @NonNull String toOuiString() {
         return String.format(
                 "%02x:%02x:%02x", (mAddr >> 40) & 0xff, (mAddr >> 32) & 0xff, (mAddr >> 24) & 0xff);
     }
@@ -197,7 +198,7 @@
         if (!isMacAddress(addr)) {
             return TYPE_UNKNOWN;
         }
-        return MacAddress.fromBytes(addr).addressType();
+        return MacAddress.fromBytes(addr).getAddressType();
     }
 
     /**
@@ -211,7 +212,7 @@
      *
      * @hide
      */
-    public static byte[] byteAddrFromStringAddr(String addr) {
+    public static @NonNull byte[] byteAddrFromStringAddr(String addr) {
         Preconditions.checkNotNull(addr);
         String[] parts = addr.split(":");
         if (parts.length != ETHER_ADDR_LEN) {
@@ -239,7 +240,7 @@
      *
      * @hide
      */
-    public static String stringAddrFromByteAddr(byte[] addr) {
+    public static @NonNull String stringAddrFromByteAddr(byte[] addr) {
         if (!isMacAddress(addr)) {
             return null;
         }
@@ -291,7 +292,7 @@
 
     // Internal conversion function equivalent to stringAddrFromByteAddr(byteAddrFromLongAddr(addr))
     // that avoids the allocation of an intermediary byte[].
-    private static String stringAddrFromLongAddr(long addr) {
+    private static @NonNull String stringAddrFromLongAddr(long addr) {
         return String.format("%02x:%02x:%02x:%02x:%02x:%02x",
                 (addr >> 40) & 0xff,
                 (addr >> 32) & 0xff,
@@ -310,7 +311,7 @@
      * @return the MacAddress corresponding to the given String representation.
      * @throws IllegalArgumentException if the given String is not a valid representation.
      */
-    public static MacAddress fromString(String addr) {
+    public static @NonNull MacAddress fromString(@NonNull String addr) {
         return new MacAddress(longAddrFromStringAddr(addr));
     }
 
@@ -322,7 +323,7 @@
      * @return the MacAddress corresponding to the given byte array representation.
      * @throws IllegalArgumentException if the given byte array is not a valid representation.
      */
-    public static MacAddress fromBytes(byte[] addr) {
+    public static @NonNull MacAddress fromBytes(@NonNull byte[] addr) {
         return new MacAddress(longAddrFromByteAddr(addr));
     }
 
@@ -336,7 +337,7 @@
      *
      * @hide
      */
-    public static MacAddress createRandomUnicastAddress() {
+    public static @NonNull MacAddress createRandomUnicastAddress() {
         return createRandomUnicastAddress(BASE_GOOGLE_MAC, new Random());
     }
 
@@ -352,7 +353,7 @@
      *
      * @hide
      */
-    public static MacAddress createRandomUnicastAddress(MacAddress base, Random r) {
+    public static @NonNull MacAddress createRandomUnicastAddress(MacAddress base, Random r) {
         long addr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong());
         addr = addr | LOCALLY_ASSIGNED_MASK;
         addr = addr & ~MULTICAST_MASK;
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 1a3ce91..5df168d 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -357,13 +357,13 @@
         // Multiple Provisioning Domains API recommendations, as made by the
         // IETF mif working group.
         //
-        // The HANDLE_MAGIC value MUST be kept in sync with the corresponding
+        // The handleMagic value MUST be kept in sync with the corresponding
         // value in the native/android/net.c NDK implementation.
         if (netId == 0) {
             return 0L;  // make this zero condition obvious for debugging
         }
-        final long HANDLE_MAGIC = 0xfacade;
-        return (((long) netId) << 32) | HANDLE_MAGIC;
+        final long handleMagic = 0xcafed00dL;
+        return (((long) netId) << 32) | handleMagic;
     }
 
     // implement the Parcelable interface
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 81c49a3..9ef26a9 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -29,7 +29,6 @@
 import android.net.wifi.WifiInfo;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.telephony.SubscriptionPlan;
 import android.util.DebugUtils;
 import android.util.Pair;
 
@@ -329,7 +328,7 @@
      * to access network when the device is idle or in battery saver mode. Otherwise, false.
      */
     public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
-        return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+        return procState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
     }
 
     /**
@@ -337,7 +336,7 @@
      * to access network when the device is in data saver mode. Otherwise, false.
      */
     public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) {
-        return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+        return procState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
     }
 
     public static String resolveNetworkId(WifiConfiguration config) {
diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java
index 7277ba3..bb36536 100644
--- a/core/java/android/net/metrics/WakeupStats.java
+++ b/core/java/android/net/metrics/WakeupStats.java
@@ -80,7 +80,7 @@
                 break;
         }
 
-        switch (ev.dstHwAddr.addressType()) {
+        switch (ev.dstHwAddr.getAddressType()) {
             case MacAddress.TYPE_UNICAST:
                 l2UnicastCount++;
                 break;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index d4d74f4..dc271d8 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -235,8 +235,11 @@
      * New in version 29:
      *   - Process states re-ordered. TOP_SLEEPING now below BACKGROUND. HEAVY_WEIGHT introduced.
      *   - CPU times per UID process state
+     * New in version 30:
+     *   - Uid.PROCESS_STATE_FOREGROUND_SERVICE only tracks
+     *   ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE.
      */
-    static final int CHECKIN_VERSION = 29;
+    static final int CHECKIN_VERSION = 30;
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
@@ -525,8 +528,8 @@
             return ActivityManager.PROCESS_STATE_NONEXISTENT;
         } else if (procState == ActivityManager.PROCESS_STATE_TOP) {
             return Uid.PROCESS_STATE_TOP;
-        } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-            // Persistent and other foreground states go here.
+        } else if (procState == ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+            // State when app has put itself in the foreground.
             return Uid.PROCESS_STATE_FOREGROUND_SERVICE;
         } else if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
             // Persistent and other foreground states go here.
@@ -694,17 +697,17 @@
         // total time a uid has had any processes running at all.
 
         /**
-         * Time this uid has any processes in the top state (or above such as persistent).
+         * Time this uid has any processes in the top state.
          */
         public static final int PROCESS_STATE_TOP = 0;
         /**
-         * Time this uid has any process with a started out bound foreground service, but
+         * Time this uid has any process with a started foreground service, but
          * none in the "top" state.
          */
         public static final int PROCESS_STATE_FOREGROUND_SERVICE = 1;
         /**
          * Time this uid has any process in an active foreground state, but none in the
-         * "top sleeping" or better state.
+         * "foreground service" or better state. Persistent and other foreground states go here.
          */
         public static final int PROCESS_STATE_FOREGROUND = 2;
         /**
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index a474b47..a5e1934 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -339,7 +339,8 @@
     /**
      * Configure name servers, search paths, and resolver parameters for the given network.
      */
-    void setDnsConfigurationForNetwork(int netId, in String[] servers, String domains);
+    void setDnsConfigurationForNetwork(int netId, in String[] servers, in String[] domains,
+            in int[] params, boolean useTls, String tlsHostname);
 
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 01d6b02..65e9473 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -97,7 +97,7 @@
     boolean isUserRunning(int userId);
     boolean isUserNameSet(int userHandle);
     boolean hasRestrictedProfiles();
-    boolean trySetQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target);
+    boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target);
     long getUserStartRealtime();
     long getUserUnlockRealtime();
 }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index cd6d41b..3798a5e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -565,6 +565,42 @@
         int OPTIONAL_SENSORS = 13;
     }
 
+    /**
+     * Either the location providers shouldn't be affected by battery saver,
+     * or battery saver is off.
+     */
+    public static final int LOCATION_MODE_NO_CHANGE = 0;
+
+    /**
+     * In this mode, the GPS based location provider should be disabled when battery saver is on and
+     * the device is non-interactive.
+     */
+    public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1;
+
+    /**
+     * All location providers should be disabled when battery saver is on and
+     * the device is non-interactive.
+     */
+    public static final int LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2;
+
+    /**
+     * In this mode, all the location providers will be kept available, but location fixes
+     * should only be provided to foreground apps.
+     */
+    public static final int LOCATION_MODE_FOREGROUND_ONLY = 3;
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"LOCATION_MODE_"}, value = {
+            LOCATION_MODE_NO_CHANGE,
+            LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF,
+            LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF,
+            LOCATION_MODE_FOREGROUND_ONLY,
+    })
+    public @interface LocationPowerSaveMode {}
+
     final Context mContext;
     final IPowerManager mService;
     final Handler mHandler;
@@ -1143,6 +1179,24 @@
     }
 
     /**
+     * Returns how location features should behave when battery saver is on. When battery saver
+     * is off, this will always return {@link #LOCATION_MODE_NO_CHANGE}.
+     *
+     * <p>This API is normally only useful for components that provide location features.
+     *
+     * @see #isPowerSaveMode()
+     * @see #ACTION_POWER_SAVE_MODE_CHANGED
+     */
+    @LocationPowerSaveMode
+    public int getLocationPowerSaveMode() {
+        final PowerSaveState powerSaveState = getPowerSaveState(ServiceType.GPS);
+        if (!powerSaveState.globalBatterySaverEnabled) {
+            return LOCATION_MODE_NO_CHANGE;
+        }
+        return powerSaveState.gpsMode;
+    }
+
+    /**
      * Returns true if the device is currently in idle mode.  This happens when a device
      * has been sitting unused and unmoving for a sufficiently long period of time, so that
      * it decides to go into a lower power-use state.  This may involve things like turning
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 44238df..7b0c153 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -209,6 +209,49 @@
     public static final String DISALLOW_AIRPLANE_MODE = "no_airplane_mode";
 
     /**
+     * Specifies if a user is disallowed from configuring brightness. When device owner sets it,
+     * it'll only be applied on the target(system) user.
+     *
+     * <p>The default value is <code>false</code>.
+     *
+     * <p>This user restriction has no effect on managed profiles.
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
+
+    /**
+     * Specifies if ambient display is disallowed for the user.
+     *
+     * <p>The default value is <code>false</code>.
+     *
+     * <p>This user restriction has no effect on managed profiles.
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_AMBIENT_DISPLAY = "no_ambient_display";
+
+    /**
+     * Specifies if a user is disallowed from changing screen off timeout.
+     *
+     * <p>The default value is <code>false</code>.
+     *
+     * <p>This user restriction has no effect on managed profiles.
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONFIG_SCREEN_TIMEOUT = "no_config_screen_timeout";
+
+    /**
      * Specifies if a user is disallowed from enabling the
      * "Unknown Sources" setting, that allows installation of apps from unknown sources.
      * The default value is <code>false</code>.
@@ -877,6 +920,27 @@
     public static final String DISALLOW_USER_SWITCH = "no_user_switch";
 
     /**
+     * Specifies whether the user can share file / picture / data from the primary user into the
+     * managed profile, either by sending them from the primary side, or by picking up data within
+     * an app in the managed profile.
+     * <p>
+     * When a managed profile is created, the system allows the user to send data from the primary
+     * side to the profile by setting up certain default cross profile intent filters. If
+     * this is undesired, this restriction can be set to disallow it. Note that this restriction
+     * will not block any sharing allowed by explicit
+     * {@link DevicePolicyManager#addCrossProfileIntentFilter} calls by the profile owner.
+     * <p>
+     * This restriction is only meaningful when set by profile owner. When it is set by device
+     * owner, it does not have any effect.
+     * <p>
+     * The default value is <code>false</code>.
+     *
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_SHARE_INTO_MANAGED_PROFILE = "no_sharing_into_profile";
+    /**
      * Application restriction key that is used to indicate the pending arrival
      * of real restrictions for the app.
      *
@@ -2194,6 +2258,12 @@
         }
     }
 
+    /** @removed */
+    @Deprecated
+    public boolean trySetQuietModeEnabled(boolean enableQuietMode, @NonNull UserHandle userHandle) {
+        return requestQuietModeEnabled(enableQuietMode, userHandle);
+    }
+
     /**
      * Enables or disables quiet mode for a managed profile. If quiet mode is enabled, apps in a
      * managed profile don't run, generate notifications, or consume data or battery.
@@ -2219,22 +2289,22 @@
      *
      * @see #isQuietModeEnabled(UserHandle)
      */
-    public boolean trySetQuietModeEnabled(boolean enableQuietMode, @NonNull UserHandle userHandle) {
-        return trySetQuietModeEnabled(enableQuietMode, userHandle, null);
+    public boolean requestQuietModeEnabled(boolean enableQuietMode, @NonNull UserHandle userHandle) {
+        return requestQuietModeEnabled(enableQuietMode, userHandle, null);
     }
 
     /**
-     * Similar to {@link #trySetQuietModeEnabled(boolean, UserHandle)}, except you can specify
+     * Similar to {@link #requestQuietModeEnabled(boolean, UserHandle)}, except you can specify
      * a target to start when user is unlocked. If {@code target} is specified, caller must have
      * the {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
-     * @see {@link #trySetQuietModeEnabled(boolean, UserHandle)}
+     * @see {@link #requestQuietModeEnabled(boolean, UserHandle)}
      * @hide
      */
-    public boolean trySetQuietModeEnabled(
+    public boolean requestQuietModeEnabled(
             boolean enableQuietMode, @NonNull UserHandle userHandle, IntentSender target) {
         try {
-            return mService.trySetQuietModeEnabled(
+            return mService.requestQuietModeEnabled(
                     mContext.getPackageName(), enableQuietMode, userHandle.getIdentifier(), target);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 340f3fb..12a495b 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -76,8 +76,8 @@
     /**
      * @return a list of VNDK snapshots supported by the framework, as
      * specified in framework manifest. For example,
-     * [("25.0.5", ["libjpeg.so", "libbase.so"]),
-     *  ("25.1.3", ["libjpeg.so", "libbase.so"])]
+     * [("27", ["libjpeg.so", "libbase.so"]),
+     *  ("28", ["libjpeg.so", "libbase.so"])]
      */
     public static native Map<String, String[]> getVndkSnapshots();
 }
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 070b8c1..839a8bf 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -394,4 +394,32 @@
         parcel.writeString(mFsUuid);
         parcel.writeString(mState);
     }
+
+    /** {@hide} */
+    public static final class ScopedAccessProviderContract {
+
+        private ScopedAccessProviderContract() {
+            throw new UnsupportedOperationException("contains constants only");
+        }
+
+        public static final String AUTHORITY = "com.android.documentsui.scopedAccess";
+
+        public static final String TABLE_PACKAGES = "packages";
+        public static final String TABLE_PERMISSIONS = "permissions";
+
+        public static final String COL_PACKAGE = "package_name";
+        public static final String COL_VOLUME_UUID = "volume_uuid";
+        public static final String COL_DIRECTORY = "directory";
+        public static final String COL_GRANTED = "granted";
+
+        public static final String[] TABLE_PACKAGES_COLUMNS = new String[] { COL_PACKAGE };
+        public static final String[] TABLE_PERMISSIONS_COLUMNS =
+                new String[] { COL_PACKAGE, COL_VOLUME_UUID, COL_DIRECTORY, COL_GRANTED };
+
+        public static final int TABLE_PACKAGES_COL_PACKAGE = 0;
+        public static final int TABLE_PERMISSIONS_COL_PACKAGE = 0;
+        public static final int TABLE_PERMISSIONS_COL_VOLUME_UUID = 1;
+        public static final int TABLE_PERMISSIONS_COL_DIRECTORY = 2;
+        public static final int TABLE_PERMISSIONS_COL_GRANTED = 3;
+    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2ec4906..6d91f59 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6802,6 +6802,37 @@
         public static final String ASSIST_DISCLOSURE_ENABLED = "assist_disclosure_enabled";
 
         /**
+         * Control if rotation suggestions are sent to System UI when in rotation locked mode.
+         * Done to enable screen rotation while the the screen rotation is locked. Enabling will
+         * poll the accelerometer in rotation locked mode.
+         *
+         * If 0, then rotation suggestions are not sent to System UI. If 1, suggestions are sent.
+         *
+         * @hide
+         */
+
+        public static final String SHOW_ROTATION_SUGGESTIONS = "show_rotation_suggestions";
+
+        /**
+         * The disabled state of SHOW_ROTATION_SUGGESTIONS.
+         * @hide
+         */
+        public static final int SHOW_ROTATION_SUGGESTIONS_DISABLED = 0x0;
+
+        /**
+         * The enabled state of SHOW_ROTATION_SUGGESTIONS.
+         * @hide
+         */
+        public static final int SHOW_ROTATION_SUGGESTIONS_ENABLED = 0x1;
+
+        /**
+         * The default state of SHOW_ROTATION_SUGGESTIONS.
+         * @hide
+         */
+        public static final int SHOW_ROTATION_SUGGESTIONS_DEFAULT =
+                SHOW_ROTATION_SUGGESTIONS_ENABLED;
+
+        /**
          * Read only list of the service components that the current user has explicitly allowed to
          * see and assist with all of the user's notifications.
          *
@@ -9622,6 +9653,17 @@
         public static final String ALWAYS_ON_DISPLAY_CONSTANTS = "always_on_display_constants";
 
         /**
+        * System VDSO global setting. This links to the "sys.vdso" system property.
+        * The following values are supported:
+        * false  -> both 32 and 64 bit vdso disabled
+        * 32     -> 32 bit vdso enabled
+        * 64     -> 64 bit vdso enabled
+        * Any other value defaults to both 32 bit and 64 bit true.
+        * @hide
+        */
+        public static final String SYS_VDSO = "sys_vdso";
+
+        /**
          * App standby (app idle) specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          * <p>
@@ -9802,6 +9844,14 @@
         public static final java.lang.String APP_STANDBY_ENABLED = "app_standby_enabled";
 
         /**
+         * Feature flag to enable or disable the Forced App Standby feature.
+         * Type: int (0 for false, 1 for true)
+         * Default: 1
+         * @hide
+         */
+        public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled";
+
+        /**
          * Whether or not Network Watchlist feature is enabled.
          * Type: int (0 for false, 1 for true)
          * Default: 0
@@ -10019,6 +10069,7 @@
          * If 1 low power mode is enabled.
          * @hide
          */
+        @TestApi
         public static final String LOW_POWER_MODE = "low_power";
 
         /**
@@ -11240,6 +11291,15 @@
          */
         public static final String ENABLE_GNSS_RAW_MEAS_FULL_TRACKING =
                 "enable_gnss_raw_meas_full_tracking";
+
+        /**
+         * Whether we've enabled zram on this device. Takes effect on
+         * reboot. The value "1" enables zram; "0" disables it, and
+         * everything else is unspecified.
+         * @hide
+         */
+        public static final String ZRAM_ENABLED =
+                "zram_enabled";
     }
 
     /**
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 6a3c55e..c568b6f 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -106,9 +106,12 @@
 
     /**
      * Broadcast intent to inform a new visual voicemail SMS has been received. This intent will
-     * only be delivered to the telephony service. {@link #EXTRA_VOICEMAIL_SMS} will be included.
-     */
-    /** @hide */
+     * only be delivered to the telephony service.
+     *
+     * @see #EXTRA_VOICEMAIL_SMS
+     * @see #EXTRA_TARGET_PACKAGE
+     *
+     * @hide */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_VOICEMAIL_SMS_RECEIVED =
             "com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED";
@@ -121,6 +124,19 @@
     public static final String EXTRA_VOICEMAIL_SMS = "android.provider.extra.VOICEMAIL_SMS";
 
     /**
+     * Extra in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} indicating the target package to bind {@link
+     * android.telephony.VisualVoicemailService}.
+     *
+     * <p>This extra should be set to android.telephony.VisualVoicemailSmsFilterSettings#packageName
+     * while performing filtering. Since the default dialer might change between the filter sending
+     * it and telephony binding to the service, this ensures the service will not receive SMS
+     * filtered by the previous app.
+     *
+     * @hide
+     */
+    public static final String EXTRA_TARGET_PACKAGE = "android.provider.extra.TARGET_PACAKGE";
+
+    /**
      * Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the
      * receiving package made this change.
      */
@@ -172,6 +188,11 @@
          */
         public static final String DURATION = Calls.DURATION;
         /**
+         * Whether or not the voicemail has been acknowledged (notification sent to the user).
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String NEW = Calls.NEW;
+        /**
          * Whether this item has been read or otherwise consumed by the user.
          * <P>Type: INTEGER (boolean)</P>
          */
diff --git a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl b/core/java/android/security/keystore/EntryRecoveryData.aidl
similarity index 88%
copy from core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl
copy to core/java/android/security/keystore/EntryRecoveryData.aidl
index bd76051..c6c20e3 100644
--- a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl
+++ b/core/java/android/security/keystore/EntryRecoveryData.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.recoverablekeystore;
+package android.security.keystore;
 
 /* @hide */
-parcelable KeyStoreRecoveryData;
+parcelable EntryRecoveryData;
diff --git a/core/java/android/security/keystore/EntryRecoveryData.java b/core/java/android/security/keystore/EntryRecoveryData.java
new file mode 100644
index 0000000..aaca3fe
--- /dev/null
+++ b/core/java/android/security/keystore/EntryRecoveryData.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Helper class with data necessary recover a single application key, given a recovery key.
+ *
+ * <ul>
+ *   <li>Alias - Keystore alias of the key.
+ *   <li>Encrypted key material.
+ * </ul>
+ *
+ * Note that Application info is not included. Recovery Agent can only make its own keys
+ * recoverable.
+ *
+ * @hide
+ */
+public final class EntryRecoveryData implements Parcelable {
+    private String mAlias;
+    // The only supported format is AES-256 symmetric key.
+    private byte[] mEncryptedKeyMaterial;
+
+    /**
+     * Builder for creating {@link EntryRecoveryData}.
+     */
+    public static class Builder {
+        private EntryRecoveryData mInstance = new EntryRecoveryData();
+
+        /**
+         * Sets Application-specific alias of the key.
+         *
+         * @param alias The alias.
+         * @return This builder.
+         */
+        public Builder setAlias(@NonNull String alias) {
+            mInstance.mAlias = alias;
+            return this;
+        }
+
+        /**
+         * Sets key material encrypted by recovery key.
+         *
+         * @param encryptedKeyMaterial The key material
+         * @return This builder
+         */
+
+        public Builder setEncryptedKeyMaterial(@NonNull byte[] encryptedKeyMaterial) {
+            mInstance.mEncryptedKeyMaterial = encryptedKeyMaterial;
+            return this;
+        }
+
+        /**
+         * Creates a new {@link EntryRecoveryData} instance.
+         *
+         * @return new instance
+         * @throws NullPointerException if some required fields were not set.
+         */
+        public @NonNull EntryRecoveryData build() {
+            Preconditions.checkNotNull(mInstance.mAlias);
+            Preconditions.checkNotNull(mInstance.mEncryptedKeyMaterial);
+            return mInstance;
+        }
+    }
+
+    private EntryRecoveryData() {
+
+    }
+
+    /**
+     * Deprecated - consider using Builder.
+     * @hide
+     */
+    public EntryRecoveryData(@NonNull String alias, @NonNull byte[] encryptedKeyMaterial) {
+        mAlias = Preconditions.checkNotNull(alias);
+        mEncryptedKeyMaterial = Preconditions.checkNotNull(encryptedKeyMaterial);
+    }
+
+    /**
+     * Application-specific alias of the key.
+     *
+     * @see java.security.KeyStore.aliases
+     */
+    public @NonNull String getAlias() {
+        return mAlias;
+    }
+
+    /** Key material encrypted by recovery key. */
+    public @NonNull byte[] getEncryptedKeyMaterial() {
+        return mEncryptedKeyMaterial;
+    }
+
+    public static final Parcelable.Creator<EntryRecoveryData> CREATOR =
+            new Parcelable.Creator<EntryRecoveryData>() {
+                public EntryRecoveryData createFromParcel(Parcel in) {
+                    return new EntryRecoveryData(in);
+                }
+
+                public EntryRecoveryData[] newArray(int length) {
+                    return new EntryRecoveryData[length];
+                }
+            };
+
+    /**
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mAlias);
+        out.writeByteArray(mEncryptedKeyMaterial);
+    }
+
+    /**
+     * @hide
+     */
+    protected EntryRecoveryData(Parcel in) {
+        mAlias = in.readString();
+        mEncryptedKeyMaterial = in.createByteArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl b/core/java/android/security/keystore/KeyDerivationParams.aidl
similarity index 88%
copy from core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl
copy to core/java/android/security/keystore/KeyDerivationParams.aidl
index bd76051..f39aa04 100644
--- a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl
+++ b/core/java/android/security/keystore/KeyDerivationParams.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.recoverablekeystore;
+package android.security.keystore;
 
 /* @hide */
-parcelable KeyStoreRecoveryData;
+parcelable KeyDerivationParams;
diff --git a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.java b/core/java/android/security/keystore/KeyDerivationParams.java
similarity index 68%
rename from core/java/android/security/recoverablekeystore/KeyDerivationParameters.java
rename to core/java/android/security/keystore/KeyDerivationParams.java
index d162455..b702acc 100644
--- a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.java
+++ b/core/java/android/security/keystore/KeyDerivationParams.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.recoverablekeystore;
+package android.security.keystore;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -28,21 +28,17 @@
 
 /**
  * Collection of parameters which define a key derivation function.
- * Supports
+ * Currently only supports salted SHA-256
  *
- * <ul>
- * <li>SHA256
- * <li>Argon2id
- * </ul>
  * @hide
  */
-public final class KeyDerivationParameters implements Parcelable {
+public final class KeyDerivationParams implements Parcelable {
     private final int mAlgorithm;
     private byte[] mSalt;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ALGORITHM_SHA256, ALGORITHM_ARGON2ID})
+    @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_ARGON2ID})
     public @interface KeyDerivationAlgorithm {
     }
 
@@ -53,6 +49,7 @@
 
     /**
      * Argon2ID
+     * @hide
      */
     // TODO: add Argon2ID support.
     public static final int ALGORITHM_ARGON2ID = 2;
@@ -60,11 +57,11 @@
     /**
      * Creates instance of the class to to derive key using salted SHA256 hash.
      */
-    public static KeyDerivationParameters createSha256Parameters(@NonNull byte[] salt) {
-        return new KeyDerivationParameters(ALGORITHM_SHA256, salt);
+    public static KeyDerivationParams createSha256Params(@NonNull byte[] salt) {
+        return new KeyDerivationParams(ALGORITHM_SHA256, salt);
     }
 
-    private KeyDerivationParameters(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) {
+    private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) {
         mAlgorithm = algorithm;
         mSalt = Preconditions.checkNotNull(salt);
     }
@@ -83,24 +80,30 @@
         return mSalt;
     }
 
-    public static final Parcelable.Creator<KeyDerivationParameters> CREATOR =
-            new Parcelable.Creator<KeyDerivationParameters>() {
-        public KeyDerivationParameters createFromParcel(Parcel in) {
-                return new KeyDerivationParameters(in);
+    public static final Parcelable.Creator<KeyDerivationParams> CREATOR =
+            new Parcelable.Creator<KeyDerivationParams>() {
+        public KeyDerivationParams createFromParcel(Parcel in) {
+                return new KeyDerivationParams(in);
         }
 
-        public KeyDerivationParameters[] newArray(int length) {
-            return new KeyDerivationParameters[length];
+        public KeyDerivationParams[] newArray(int length) {
+            return new KeyDerivationParams[length];
         }
     };
 
+    /**
+     * @hide
+     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mAlgorithm);
         out.writeByteArray(mSalt);
     }
 
-    protected KeyDerivationParameters(Parcel in) {
+    /**
+     * @hide
+     */
+    protected KeyDerivationParams(Parcel in) {
         mAlgorithm = in.readInt();
         mSalt = in.createByteArray();
     }
diff --git a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl b/core/java/android/security/keystore/RecoveryData.aidl
similarity index 88%
rename from core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl
rename to core/java/android/security/keystore/RecoveryData.aidl
index bd76051..4200de1 100644
--- a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl
+++ b/core/java/android/security/keystore/RecoveryData.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.recoverablekeystore;
+package android.security.keystore;
 
 /* @hide */
-parcelable KeyStoreRecoveryData;
+parcelable RecoveryData;
diff --git a/core/java/android/security/keystore/RecoveryData.java b/core/java/android/security/keystore/RecoveryData.java
new file mode 100644
index 0000000..897aa18
--- /dev/null
+++ b/core/java/android/security/keystore/RecoveryData.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Helper class which returns data necessary to recover keys.
+ * Contains
+ *
+ * <ul>
+ * <li>Snapshot version.
+ * <li>Recovery metadata with UI and key derivation parameters.
+ * <li>List of application keys encrypted by recovery key.
+ * <li>Encrypted recovery key.
+ * </ul>
+ *
+ * @hide
+ */
+public final class RecoveryData implements Parcelable {
+    private int mSnapshotVersion;
+    private List<RecoveryMetadata> mRecoveryMetadata;
+    private List<EntryRecoveryData> mEntryRecoveryData;
+    private byte[] mEncryptedRecoveryKeyBlob;
+
+    /**
+     * @hide
+     * Deprecated, consider using builder.
+     */
+    public RecoveryData(
+            int snapshotVersion,
+            @NonNull List<RecoveryMetadata> recoveryMetadata,
+            @NonNull List<EntryRecoveryData> entryRecoveryData,
+            @NonNull byte[] encryptedRecoveryKeyBlob) {
+        mSnapshotVersion = snapshotVersion;
+        mRecoveryMetadata =
+                Preconditions.checkCollectionElementsNotNull(recoveryMetadata, "recoveryMetadata");
+        mEntryRecoveryData = Preconditions.checkCollectionElementsNotNull(entryRecoveryData,
+                "entryRecoveryData");
+        mEncryptedRecoveryKeyBlob = Preconditions.checkNotNull(encryptedRecoveryKeyBlob);
+    }
+
+    private RecoveryData() {
+
+    }
+
+    /**
+     * Snapshot version for given account. It is incremented when user secret or list of application
+     * keys changes.
+     */
+    public int getSnapshotVersion() {
+        return mSnapshotVersion;
+    }
+
+    /**
+     * UI and key derivation parameters. Note that combination of secrets may be used.
+     */
+    public @NonNull List<RecoveryMetadata> getRecoveryMetadata() {
+        return mRecoveryMetadata;
+    }
+
+    /**
+     * List of application keys, with key material encrypted by
+     * the recovery key ({@link #getEncryptedRecoveryKeyBlob}).
+     */
+    public @NonNull List<EntryRecoveryData> getEntryRecoveryData() {
+        return mEntryRecoveryData;
+    }
+
+    /**
+     * Recovery key blob, encrypted by user secret and recovery service public key.
+     */
+    public @NonNull byte[] getEncryptedRecoveryKeyBlob() {
+        return mEncryptedRecoveryKeyBlob;
+    }
+
+    public static final Parcelable.Creator<RecoveryData> CREATOR =
+            new Parcelable.Creator<RecoveryData>() {
+        public RecoveryData createFromParcel(Parcel in) {
+            return new RecoveryData(in);
+        }
+
+        public RecoveryData[] newArray(int length) {
+            return new RecoveryData[length];
+        }
+    };
+
+    /**
+     * Builder for creating {@link RecoveryData}.
+     */
+    public static class Builder {
+        private RecoveryData mInstance = new RecoveryData();
+
+        /**
+         * Snapshot version for given account.
+         *
+         * @param snapshotVersion The snapshot version
+         * @return This builder.
+         */
+        public Builder setSnapshotVersion(int snapshotVersion) {
+            mInstance.mSnapshotVersion = snapshotVersion;
+            return this;
+        }
+
+        /**
+         * Sets UI and key derivation parameters
+         *
+         * @param recoveryMetadata The UI and key derivation parameters
+         * @return This builder.
+         */
+        public Builder setRecoveryMetadata(@NonNull List<RecoveryMetadata> recoveryMetadata) {
+            mInstance.mRecoveryMetadata = recoveryMetadata;
+            return this;
+        }
+
+        /**
+         * List of application keys.
+         *
+         * @param entryRecoveryData List of application keys
+         * @return This builder.
+         */
+        public Builder setEntryRecoveryData(List<EntryRecoveryData> entryRecoveryData) {
+            mInstance.mEntryRecoveryData = entryRecoveryData;
+            return this;
+        }
+
+        /**
+         * Sets recovery key blob
+         *
+         * @param encryptedRecoveryKeyBlob The recovery key blob.
+         * @return This builder.
+         */
+        public Builder setEncryptedRecoveryKeyBlob(@NonNull byte[] encryptedRecoveryKeyBlob) {
+            mInstance.mEncryptedRecoveryKeyBlob = encryptedRecoveryKeyBlob;
+            return this;
+        }
+
+
+        /**
+         * Creates a new {@link RecoveryData} instance.
+         *
+         * @return new instance
+         * @throws NullPointerException if some required fields were not set.
+         */
+        public @NonNull RecoveryData build() {
+            Preconditions.checkCollectionElementsNotNull(mInstance.mRecoveryMetadata,
+                    "recoveryMetadata");
+            Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData,
+                    "entryRecoveryData");
+            Preconditions.checkNotNull(mInstance.mEncryptedRecoveryKeyBlob);
+            return mInstance;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mSnapshotVersion);
+        out.writeTypedList(mRecoveryMetadata);
+        out.writeByteArray(mEncryptedRecoveryKeyBlob);
+        out.writeTypedList(mEntryRecoveryData);
+    }
+
+    /**
+     * @hide
+     */
+    protected RecoveryData(Parcel in) {
+        mSnapshotVersion = in.readInt();
+        mRecoveryMetadata = in.createTypedArrayList(RecoveryMetadata.CREATOR);
+        mEncryptedRecoveryKeyBlob = in.createByteArray();
+        mEntryRecoveryData = in.createTypedArrayList(EntryRecoveryData.CREATOR);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/security/keystore/RecoveryManager.java b/core/java/android/security/keystore/RecoveryManager.java
new file mode 100644
index 0000000..99bd284
--- /dev/null
+++ b/core/java/android/security/keystore/RecoveryManager.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+
+import com.android.internal.widget.ILockSettings;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A wrapper around KeyStore which lets key be exported to trusted hardware on server side and
+ * recovered later.
+ *
+ * @hide
+ */
+public class RecoveryManager {
+
+    /** Key has been successfully synced. */
+    public static final int RECOVERY_STATUS_SYNCED = 0;
+    /** Waiting for recovery agent to sync the key. */
+    public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1;
+    /** Recovery account is not available. */
+    public static final int RECOVERY_STATUS_MISSING_ACCOUNT = 2;
+    /** Key cannot be synced. */
+    public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3;
+
+    private final ILockSettings mBinder;
+
+    private RecoveryManager(ILockSettings binder) {
+        mBinder = binder;
+    }
+
+    /**
+     * Gets a new instance of the class.
+     */
+    public static RecoveryManager getInstance() {
+        ILockSettings lockSettings =
+                ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
+        return new RecoveryManager(lockSettings);
+    }
+
+    /**
+     * Initializes key recovery service for the calling application. RecoveryManager
+     * randomly chooses one of the keys from the list and keeps it to use for future key export
+     * operations. Collection of all keys in the list must be signed by the provided {@code
+     * rootCertificateAlias}, which must also be present in the list of root certificates
+     * preinstalled on the device. The random selection allows RecoveryManager to select
+     * which of a set of remote recovery service devices will be used.
+     *
+     * <p>In addition, RecoveryManager enforces a delay of three months between
+     * consecutive initialization attempts, to limit the ability of an attacker to often switch
+     * remote recovery devices and significantly increase number of recovery attempts.
+     *
+     * @param rootCertificateAlias alias of a root certificate preinstalled on the device
+     * @param signedPublicKeyList binary blob a list of X509 certificates and signature
+     * @throws RecoveryManagerException if signature is invalid, or key rotation was rate
+     *     limited.
+     * @hide
+     */
+    public void initRecoveryService(
+            @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
+            throws RecoveryManagerException {
+        try {
+            mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Returns data necessary to store all recoverable keys for given account. Key material is
+     * encrypted with user secret and recovery public key.
+     *
+     * @param account specific to Recovery agent.
+     * @return Data necessary to recover keystore.
+     * @hide
+     */
+    public @NonNull RecoveryData getRecoveryData(@NonNull byte[] account)
+            throws RecoveryManagerException {
+        try {
+            RecoveryData recoveryData = mBinder.getRecoveryData(account);
+            return recoveryData;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Sets a listener which notifies recovery agent that new recovery snapshot is available. {@link
+     * #getRecoveryData} can be used to get the snapshot. Note that every recovery agent can have at
+     * most one registered listener at any time.
+     *
+     * @param intent triggered when new snapshot is available. Unregisters listener if the value is
+     *     {@code null}.
+     * @hide
+     */
+    public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
+            throws RecoveryManagerException {
+        try {
+            mBinder.setSnapshotCreatedPendingIntent(intent);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Returns a map from recovery agent accounts to corresponding KeyStore recovery snapshot
+     * version. Version zero is used, if no snapshots were created for the account.
+     *
+     * @return Map from recovery agent accounts to snapshot versions.
+     * @see RecoveryData#getSnapshotVersion
+     * @hide
+     */
+    public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions()
+            throws RecoveryManagerException {
+        try {
+            // IPC doesn't support generic Maps.
+            @SuppressWarnings("unchecked")
+            Map<byte[], Integer> result =
+                    (Map<byte[], Integer>) mBinder.getRecoverySnapshotVersions();
+            return result;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Server parameters used to generate new recovery key blobs. This value will be included in
+     * {@code RecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included
+     * in vaultParams {@link #startRecoverySession}
+     *
+     * @param serverParams included in recovery key blob.
+     * @see #getRecoveryData
+     * @throws RecoveryManagerException If parameters rotation is rate limited.
+     * @hide
+     */
+    public void setServerParams(byte[] serverParams) throws RecoveryManagerException {
+        try {
+            mBinder.setServerParams(serverParams);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Updates recovery status for given keys. It is used to notify keystore that key was
+     * successfully stored on the server or there were an error. Application can check this value
+     * using {@code getRecoveyStatus}.
+     *
+     * @param packageName Application whose recoverable keys' statuses are to be updated.
+     * @param aliases List of application-specific key aliases. If the array is empty, updates the
+     *     status for all existing recoverable keys.
+     * @param status Status specific to recovery agent.
+     */
+    public void setRecoveryStatus(
+            @NonNull String packageName, @Nullable String[] aliases, int status)
+            throws NameNotFoundException, RecoveryManagerException {
+        try {
+            mBinder.setRecoveryStatus(packageName, aliases, status);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Returns a {@code Map} from Application's KeyStore key aliases to their recovery status.
+     * Negative status values are reserved for recovery agent specific codes. List of common codes:
+     *
+     * <ul>
+     *   <li>{@link #RECOVERY_STATUS_SYNCED}
+     *   <li>{@link #RECOVERY_STATUS_SYNC_IN_PROGRESS}
+     *   <li>{@link #RECOVERY_STATUS_MISSING_ACCOUNT}
+     *   <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE}
+     * </ul>
+     *
+     * @return {@code Map} from KeyStore alias to recovery status.
+     * @see #setRecoveryStatus
+     * @hide
+     */
+    public Map<String, Integer> getRecoveryStatus()
+            throws RecoveryManagerException {
+        try {
+            // IPC doesn't support generic Maps.
+            @SuppressWarnings("unchecked")
+            Map<String, Integer> result =
+                    (Map<String, Integer>) mBinder.getRecoveryStatus(/*packageName=*/ null);
+            return result;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them
+     * is necessary to recover data.
+     *
+     * @param secretTypes {@link RecoveryMetadata#TYPE_LOCKSCREEN} or {@link
+     *     RecoveryMetadata#TYPE_CUSTOM_PASSWORD}
+     */
+    public void setRecoverySecretTypes(
+            @NonNull @RecoveryMetadata.UserSecretType int[] secretTypes)
+            throws RecoveryManagerException {
+        try {
+            mBinder.setRecoverySecretTypes(secretTypes);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Defines a set of secret types used for end-to-end keystore encryption. Knowing all of them is
+     * necessary to generate RecoveryData.
+     *
+     * @return list of recovery secret types
+     * @see RecoveryData
+     */
+    public @NonNull @RecoveryMetadata.UserSecretType int[] getRecoverySecretTypes()
+            throws RecoveryManagerException {
+        try {
+            return mBinder.getRecoverySecretTypes();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Returns a list of recovery secret types, necessary to create a pending recovery snapshot.
+     * When user enters a secret of a pending type {@link #recoverySecretAvailable} should be
+     * called.
+     *
+     * @return list of recovery secret types
+     * @hide
+     */
+    public @NonNull @RecoveryMetadata.UserSecretType int[] getPendingRecoverySecretTypes()
+            throws RecoveryManagerException {
+        try {
+            return mBinder.getPendingRecoverySecretTypes();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Method notifies KeyStore that a user-generated secret is available. This method generates a
+     * symmetric session key which a trusted remote device can use to return a recovery key. Caller
+     * should use {@link RecoveryMetadata#clearSecret} to override the secret value in
+     * memory.
+     *
+     * @param recoverySecret user generated secret together with parameters necessary to regenerate
+     *     it on a new device.
+     * @hide
+     */
+    public void recoverySecretAvailable(@NonNull RecoveryMetadata recoverySecret)
+            throws RecoveryManagerException {
+        try {
+            mBinder.recoverySecretAvailable(recoverySecret);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Initializes recovery session and returns a blob with proof of recovery secrets possession.
+     * The method generates symmetric key for a session, which trusted remote device can use to
+     * return recovery key.
+     *
+     * @param sessionId ID for recovery session.
+     * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key
+     * used to create the recovery blob on the source device.
+     * Keystore will verify the certificate using root of trust.
+     * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
+     *     Used to limit number of guesses.
+     * @param vaultChallenge Data passed from server for this recovery session and used to prevent
+     *     replay attacks
+     * @param secrets Secrets provided by user, the method only uses type and secret fields.
+     * @return Binary blob with recovery claim. It is encrypted with verifierPublicKey and contains
+     *     a proof of user secrets, session symmetric key and parameters necessary to identify the
+     *     counter with the number of failed recovery attempts.
+     */
+    public @NonNull byte[] startRecoverySession(
+            @NonNull String sessionId,
+            @NonNull byte[] verifierPublicKey,
+            @NonNull byte[] vaultParams,
+            @NonNull byte[] vaultChallenge,
+            @NonNull List<RecoveryMetadata> secrets)
+            throws RecoveryManagerException {
+        try {
+            byte[] recoveryClaim =
+                    mBinder.startRecoverySession(
+                            sessionId,
+                            verifierPublicKey,
+                            vaultParams,
+                            vaultChallenge,
+                            secrets);
+            return recoveryClaim;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Imports keys.
+     *
+     * @param sessionId Id for recovery session, same as in
+     *     {@link #startRecoverySession(String, byte[], byte[], byte[], List)}.
+     * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
+     * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
+     *     and session. KeyStore only uses package names from the application info in {@link
+     *     EntryRecoveryData}. Caller is responsibility to perform certificates check.
+     * @return Map from alias to raw key material.
+     */
+    public Map<String, byte[]> recoverKeys(
+            @NonNull String sessionId,
+            @NonNull byte[] recoveryKeyBlob,
+            @NonNull List<EntryRecoveryData> applicationKeys)
+            throws RecoveryManagerException {
+        try {
+            return (Map<String, byte[]>) mBinder.recoverKeys(
+                    sessionId, recoveryKeyBlob, applicationKeys);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Generates a key called {@code alias} and loads it into the recoverable key store. Returns the
+     * raw material of the key.
+     *
+     * @param alias The key alias.
+     * @throws RecoveryManagerException if an error occurred generating and storing the
+     *     key.
+     */
+    public byte[] generateAndStoreKey(@NonNull String alias)
+            throws RecoveryManagerException {
+        try {
+            return mBinder.generateAndStoreKey(alias);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Removes a key called {@code alias} from the recoverable key store.
+     *
+     * @param alias The key alias.
+     */
+    public void removeKey(@NonNull String alias) throws RecoveryManagerException {
+        try {
+            mBinder.removeKey(alias);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw RecoveryManagerException.fromServiceSpecificException(e);
+        }
+    }
+}
diff --git a/core/java/android/security/keystore/RecoveryManagerException.java b/core/java/android/security/keystore/RecoveryManagerException.java
new file mode 100644
index 0000000..344718a
--- /dev/null
+++ b/core/java/android/security/keystore/RecoveryManagerException.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.os.ServiceSpecificException;
+
+/**
+ * Exception thrown by {@link RecoveryManager} methods.
+ *
+ * @hide
+ */
+public class RecoveryManagerException extends Exception {
+    /**
+     * Failed because the loader has not been initialized with a recovery public key yet.
+     */
+    public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20;
+
+    /**
+     * Failed because no snapshot is yet pending to be synced for the user.
+     */
+    public static final int ERROR_NO_SNAPSHOT_PENDING = 21;
+
+    /**
+     * Failed due to an error internal to AndroidKeyStore.
+     */
+    public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22;
+
+    /**
+     * Failed because the user does not have a lock screen set.
+     */
+    public static final int ERROR_INSECURE_USER = 24;
+
+    /**
+     * Failed because of an internal database error.
+     */
+    public static final int ERROR_DATABASE_ERROR = 25;
+
+    /**
+     * Failed because the provided certificate was not a valid X509 certificate.
+     */
+    public static final int ERROR_BAD_X509_CERTIFICATE = 26;
+
+    /**
+     * Should never be thrown - some algorithm that all AOSP implementations must support is
+     * not available.
+     */
+    public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27;
+
+    /**
+     * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong,
+     * the data has become corrupted, the data has been tampered with, etc.
+     */
+    public static final int ERROR_DECRYPTION_FAILED = 28;
+
+    /**
+     * Rate limit is enforced to prevent using too many trusted remote devices, since each device
+     * can have its own number of user secret guesses allowed.
+     *
+     * @hide
+     */
+    public static final int ERROR_RATE_LIMIT_EXCEEDED = 29;
+
+    private int mErrorCode;
+
+    /**
+     * Creates new {@link #RecoveryManagerException} instance from the error code.
+     *
+     * @param errorCode An error code, as listed at the top of this file.
+     * @param message The associated error message.
+     * @hide
+     */
+    public static RecoveryManagerException fromErrorCode(
+            int errorCode, String message) {
+        return new RecoveryManagerException(errorCode, message);
+    }
+    /**
+     * Creates new {@link #RecoveryManagerException} from {@link
+     * ServiceSpecificException}.
+     *
+     * @param e exception thrown on service side.
+     * @hide
+     */
+    static RecoveryManagerException fromServiceSpecificException(
+            ServiceSpecificException e) throws RecoveryManagerException {
+        throw RecoveryManagerException.fromErrorCode(e.errorCode, e.getMessage());
+    }
+
+    private RecoveryManagerException(int errorCode, String message) {
+        super(message);
+        mErrorCode = errorCode;
+    }
+
+    /** Returns errorCode. */
+    public int getErrorCode() {
+        return mErrorCode;
+    }
+}
diff --git a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl b/core/java/android/security/keystore/RecoveryMetadata.aidl
similarity index 88%
copy from core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl
copy to core/java/android/security/keystore/RecoveryMetadata.aidl
index bd76051..8e342b4 100644
--- a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.aidl
+++ b/core/java/android/security/keystore/RecoveryMetadata.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.recoverablekeystore;
+package android.security.keystore;
 
 /* @hide */
-parcelable KeyStoreRecoveryData;
+parcelable RecoveryMetadata;
diff --git a/core/java/android/security/keystore/RecoveryMetadata.java b/core/java/android/security/keystore/RecoveryMetadata.java
new file mode 100644
index 0000000..3f09455
--- /dev/null
+++ b/core/java/android/security/keystore/RecoveryMetadata.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/**
+ * Helper class with data necessary to recover Keystore on a new device.
+ * It defines UI shown to the user and a way to derive a cryptographic key from user output.
+ *
+ * @hide
+ */
+public final class RecoveryMetadata implements Parcelable {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({TYPE_LOCKSCREEN, TYPE_CUSTOM_PASSWORD})
+    public @interface UserSecretType {
+    }
+
+    /**
+     * Lockscreen secret is required to recover KeyStore.
+     */
+    public static final int TYPE_LOCKSCREEN = 100;
+
+    /**
+     * Custom passphrase, unrelated to lock screen, is required to recover KeyStore.
+     */
+    public static final int TYPE_CUSTOM_PASSWORD = 101;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({TYPE_PIN, TYPE_PASSWORD, TYPE_PATTERN})
+    public @interface LockScreenUiFormat {
+    }
+
+    /**
+     * Pin with digits only.
+     */
+    public static final int TYPE_PIN = 1;
+
+    /**
+     * Password. String with latin-1 characters only.
+     */
+    public static final int TYPE_PASSWORD = 2;
+
+    /**
+     * Pattern with 3 by 3 grid.
+     */
+    public static final int TYPE_PATTERN = 3;
+
+    @UserSecretType
+    private Integer mUserSecretType;
+
+    @LockScreenUiFormat
+    private Integer mLockScreenUiFormat;
+
+    /**
+     * Parameters of the key derivation function, including algorithm, difficulty, salt.
+     */
+    private KeyDerivationParams mKeyDerivationParams;
+    private byte[] mSecret; // Derived from user secret. The field must have limited visibility.
+
+    /**
+     * @param secret Constructor creates a reference to the secret. Caller must use
+     * @link {#clearSecret} to overwrite its value in memory.
+     * @hide
+     */
+    public RecoveryMetadata(@UserSecretType int userSecretType,
+            @LockScreenUiFormat int lockScreenUiFormat,
+            @NonNull KeyDerivationParams keyDerivationParams,
+            @NonNull byte[] secret) {
+        mUserSecretType = userSecretType;
+        mLockScreenUiFormat = lockScreenUiFormat;
+        mKeyDerivationParams = Preconditions.checkNotNull(keyDerivationParams);
+        mSecret = Preconditions.checkNotNull(secret);
+    }
+
+    private RecoveryMetadata() {
+
+    }
+
+    /**
+     * @see TYPE_LOCKSCREEN
+     * @see TYPE_CUSTOM_PASSWORD
+     */
+    public @UserSecretType int getUserSecretType() {
+        return mUserSecretType;
+    }
+
+    /**
+     * Specifies UX shown to user during recovery.
+     * Default value is {@code TYPE_LOCKSCREEN}
+     *
+     * @see TYPE_PIN
+     * @see TYPE_PASSWORD
+     * @see TYPE_PATTERN
+     */
+    public @LockScreenUiFormat int getLockScreenUiFormat() {
+        return mLockScreenUiFormat;
+    }
+
+    /**
+     * Specifies function used to derive symmetric key from user input
+     * Format is defined in separate util class.
+     */
+    public @NonNull KeyDerivationParams getKeyDerivationParams() {
+        return mKeyDerivationParams;
+    }
+
+    /**
+     * Secret derived from user input.
+     * Default value is empty array
+     *
+     * @return secret or empty array
+     */
+    public @NonNull byte[] getSecret() {
+        return mSecret;
+    }
+
+    /**
+     * Builder for creating {@link RecoveryMetadata}.
+     */
+    public static class Builder {
+        private RecoveryMetadata mInstance = new RecoveryMetadata();
+
+        /**
+         * Sets user secret type.
+         *
+         * @see TYPE_LOCKSCREEN
+         * @see TYPE_CUSTOM_PASSWORD
+         * @param userSecretType The secret type
+         * @return This builder.
+         */
+        public Builder setUserSecretType(@UserSecretType int userSecretType) {
+            mInstance.mUserSecretType = userSecretType;
+            return this;
+        }
+
+        /**
+         * Sets UI format.
+         *
+         * @see TYPE_PIN
+         * @see TYPE_PASSWORD
+         * @see TYPE_PATTERN
+         * @param lockScreenUiFormat The UI format
+         * @return This builder.
+         */
+        public Builder setLockScreenUiFormat(@LockScreenUiFormat int lockScreenUiFormat) {
+            mInstance.mLockScreenUiFormat = lockScreenUiFormat;
+            return this;
+        }
+
+        /**
+         * Sets parameters of the key derivation function.
+         *
+         * @param keyDerivationParams Key derivation Params
+         * @return This builder.
+         */
+        public Builder setKeyDerivationParams(@NonNull KeyDerivationParams
+                keyDerivationParams) {
+            mInstance.mKeyDerivationParams = keyDerivationParams;
+            return this;
+        }
+
+        /**
+         * Secret derived from user input, or empty array.
+         *
+         * @param secret The secret.
+         * @return This builder.
+         */
+        public Builder setSecret(@NonNull byte[] secret) {
+            mInstance.mSecret = secret;
+            return this;
+        }
+
+
+        /**
+         * Creates a new {@link RecoveryMetadata} instance.
+         * The instance will include default values, if {@link setSecret}
+         * or {@link setUserSecretType} were not called.
+         *
+         * @return new instance
+         * @throws NullPointerException if some required fields were not set.
+         */
+        public @NonNull RecoveryMetadata build() {
+            if (mInstance.mUserSecretType == null) {
+                mInstance.mUserSecretType = TYPE_LOCKSCREEN;
+            }
+            Preconditions.checkNotNull(mInstance.mLockScreenUiFormat);
+            Preconditions.checkNotNull(mInstance.mKeyDerivationParams);
+            if (mInstance.mSecret == null) {
+                mInstance.mSecret = new byte[]{};
+            }
+            return mInstance;
+        }
+    }
+
+    /**
+     * Removes secret from memory than object is no longer used.
+     * Since finalizer call is not reliable, please use @link {#clearSecret} directly.
+     */
+    @Override
+    protected void finalize() throws Throwable {
+        clearSecret();
+        super.finalize();
+    }
+
+    /**
+     * Fills mSecret with zeroes.
+     */
+    public void clearSecret() {
+        Arrays.fill(mSecret, (byte) 0);
+    }
+
+    public static final Parcelable.Creator<RecoveryMetadata> CREATOR =
+            new Parcelable.Creator<RecoveryMetadata>() {
+        public RecoveryMetadata createFromParcel(Parcel in) {
+            return new RecoveryMetadata(in);
+        }
+
+        public RecoveryMetadata[] newArray(int length) {
+            return new RecoveryMetadata[length];
+        }
+    };
+
+    /**
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mUserSecretType);
+        out.writeInt(mLockScreenUiFormat);
+        out.writeTypedObject(mKeyDerivationParams, flags);
+        out.writeByteArray(mSecret);
+    }
+
+    /**
+     * @hide
+     */
+    protected RecoveryMetadata(Parcel in) {
+        mUserSecretType = in.readInt();
+        mLockScreenUiFormat = in.readInt();
+        mKeyDerivationParams = in.readTypedObject(KeyDerivationParams.CREATOR);
+        mSecret = in.createByteArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/security/recoverablekeystore/KeyEntryRecoveryData.aidl b/core/java/android/security/recoverablekeystore/KeyEntryRecoveryData.aidl
deleted file mode 100644
index 1674e51..0000000
--- a/core/java/android/security/recoverablekeystore/KeyEntryRecoveryData.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.recoverablekeystore;
-
-/* @hide */
-parcelable KeyEntryRecoveryData;
diff --git a/core/java/android/security/recoverablekeystore/KeyEntryRecoveryData.java b/core/java/android/security/recoverablekeystore/KeyEntryRecoveryData.java
deleted file mode 100644
index 5f56c91..0000000
--- a/core/java/android/security/recoverablekeystore/KeyEntryRecoveryData.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.recoverablekeystore;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-/**
- * Helper class with data necessary recover a single application key, given a recovery key.
- *
- * <ul>
- *   <li>Alias - Keystore alias of the key.
- *   <li>Encrypted key material.
- * </ul>
- *
- * Note that Application info is not included. Recovery Agent can only make its own keys
- * recoverable.
- *
- * @hide
- */
-public final class KeyEntryRecoveryData implements Parcelable {
-    private final String mAlias;
-    // The only supported format is AES-256 symmetric key.
-    private final byte[] mEncryptedKeyMaterial;
-
-    public KeyEntryRecoveryData(@NonNull String alias, @NonNull byte[] encryptedKeyMaterial) {
-        mAlias = Preconditions.checkNotNull(alias);
-        mEncryptedKeyMaterial = Preconditions.checkNotNull(encryptedKeyMaterial);
-    }
-
-    /**
-     * Application-specific alias of the key.
-     *
-     * @see java.security.KeyStore.aliases
-     */
-    public @NonNull String getAlias() {
-        return mAlias;
-    }
-
-    /** Encrypted key material encrypted by recovery key. */
-    public @NonNull byte[] getEncryptedKeyMaterial() {
-        return mEncryptedKeyMaterial;
-    }
-
-    public static final Parcelable.Creator<KeyEntryRecoveryData> CREATOR =
-            new Parcelable.Creator<KeyEntryRecoveryData>() {
-                public KeyEntryRecoveryData createFromParcel(Parcel in) {
-                    return new KeyEntryRecoveryData(in);
-                }
-
-                public KeyEntryRecoveryData[] newArray(int length) {
-                    return new KeyEntryRecoveryData[length];
-                }
-            };
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mAlias);
-        out.writeByteArray(mEncryptedKeyMaterial);
-    }
-
-    protected KeyEntryRecoveryData(Parcel in) {
-        mAlias = in.readString();
-        mEncryptedKeyMaterial = in.createByteArray();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-}
diff --git a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.java b/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.java
deleted file mode 100644
index 087f7a2..0000000
--- a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryData.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.recoverablekeystore;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.List;
-
-/**
- * Helper class which returns data necessary to recover keys.
- * Contains
- *
- * <ul>
- * <li>Snapshot version.
- * <li>Recovery metadata with UI and key derivation parameters.
- * <li>List of application keys encrypted by recovery key.
- * <li>Encrypted recovery key.
- * </ul>
- *
- * @hide
- */
-public final class KeyStoreRecoveryData implements Parcelable {
-    private final int mSnapshotVersion;
-    private final List<KeyStoreRecoveryMetadata> mRecoveryMetadata;
-    private final List<KeyEntryRecoveryData> mApplicationKeyBlobs;
-    private final byte[] mEncryptedRecoveryKeyBlob;
-
-    public KeyStoreRecoveryData(int snapshotVersion, @NonNull List<KeyStoreRecoveryMetadata>
-            recoveryMetadata, @NonNull List<KeyEntryRecoveryData> applicationKeyBlobs,
-            @NonNull byte[] encryptedRecoveryKeyBlob) {
-        mSnapshotVersion = snapshotVersion;
-        mRecoveryMetadata = Preconditions.checkNotNull(recoveryMetadata);
-        mApplicationKeyBlobs = Preconditions.checkNotNull(applicationKeyBlobs);
-        mEncryptedRecoveryKeyBlob = Preconditions.checkNotNull(encryptedRecoveryKeyBlob);
-    }
-
-    /**
-     * Snapshot version for given account. It is incremented when user secret or list of application
-     * keys changes.
-     */
-    public int getSnapshotVersion() {
-        return mSnapshotVersion;
-    }
-
-    /**
-     * UI and key derivation parameters. Note that combination of secrets may be used.
-     */
-    public @NonNull List<KeyStoreRecoveryMetadata> getRecoveryMetadata() {
-        return mRecoveryMetadata;
-    }
-
-    /**
-     * List of application keys, with key material encrypted by
-     * the recovery key ({@link #getEncryptedRecoveryKeyBlob}).
-     */
-    public @NonNull List<KeyEntryRecoveryData> getApplicationKeyBlobs() {
-        return mApplicationKeyBlobs;
-    }
-
-    /**
-     * Recovery key blob, encrypted by user secret and recovery service public key.
-     */
-    public @NonNull byte[] getEncryptedRecoveryKeyBlob() {
-        return mEncryptedRecoveryKeyBlob;
-    }
-
-    public static final Parcelable.Creator<KeyStoreRecoveryData> CREATOR =
-            new Parcelable.Creator<KeyStoreRecoveryData>() {
-        public KeyStoreRecoveryData createFromParcel(Parcel in) {
-            return new KeyStoreRecoveryData(in);
-        }
-
-        public KeyStoreRecoveryData[] newArray(int length) {
-            return new KeyStoreRecoveryData[length];
-        }
-    };
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mSnapshotVersion);
-        out.writeTypedList(mRecoveryMetadata);
-        out.writeByteArray(mEncryptedRecoveryKeyBlob);
-        out.writeTypedList(mApplicationKeyBlobs);
-    }
-
-    protected KeyStoreRecoveryData(Parcel in) {
-        mSnapshotVersion = in.readInt();
-        mRecoveryMetadata = in.createTypedArrayList(KeyStoreRecoveryMetadata.CREATOR);
-        mEncryptedRecoveryKeyBlob = in.createByteArray();
-        mApplicationKeyBlobs = in.createTypedArrayList(KeyEntryRecoveryData.CREATOR);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-}
diff --git a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryMetadata.aidl b/core/java/android/security/recoverablekeystore/KeyStoreRecoveryMetadata.aidl
deleted file mode 100644
index e1d49de..0000000
--- a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryMetadata.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.recoverablekeystore;
-
-/* @hide */
-parcelable KeyStoreRecoveryMetadata;
diff --git a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryMetadata.java b/core/java/android/security/recoverablekeystore/KeyStoreRecoveryMetadata.java
deleted file mode 100644
index 43f9c80..0000000
--- a/core/java/android/security/recoverablekeystore/KeyStoreRecoveryMetadata.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.recoverablekeystore;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-
-/**
- * Helper class with data necessary to recover Keystore on a new device.
- * It defines UI shown to the user and a way to derive a cryptographic key from user output.
- *
- * @hide
- */
-public final class KeyStoreRecoveryMetadata implements Parcelable {
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TYPE_LOCKSCREEN, TYPE_CUSTOM_PASSWORD})
-    public @interface UserSecretType {
-    }
-
-    /**
-     * Lockscreen secret is required to recover KeyStore.
-     */
-    public static final int TYPE_LOCKSCREEN = 1;
-
-    /**
-     * Custom passphrase, unrelated to lock screen, is required to recover KeyStore.
-     */
-    public static final int TYPE_CUSTOM_PASSWORD = 2;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TYPE_PIN, TYPE_PASSWORD, TYPE_PATTERN})
-    public @interface LockScreenUiFormat {
-    }
-
-    /**
-     * Pin with digits only.
-     */
-    public static final int TYPE_PIN = 1;
-
-    /**
-     * Password. String with latin-1 characters only.
-     */
-    public static final int TYPE_PASSWORD = 2;
-
-    /**
-     * Pattern with 3 by 3 grid.
-     */
-    public static final int TYPE_PATTERN = 3;
-
-    @UserSecretType
-    private final int mUserSecretType;
-
-    @LockScreenUiFormat
-    private final int mLockScreenUiFormat;
-
-    /**
-     * Parameters of key derivation function, including algorithm, difficulty, salt.
-     */
-    private KeyDerivationParameters mKeyDerivationParameters;
-    private byte[] mSecret; // Derived from user secret. The field must have limited visibility.
-
-    /**
-     * @param secret Constructor creates a reference to the secret. Caller must use
-     * @link {#clearSecret} to overwrite its value in memory.
-     */
-    public KeyStoreRecoveryMetadata(@UserSecretType int userSecretType,
-            @LockScreenUiFormat int lockScreenUiFormat,
-            @NonNull KeyDerivationParameters keyDerivationParameters, @NonNull byte[] secret) {
-        mUserSecretType = userSecretType;
-        mLockScreenUiFormat = lockScreenUiFormat;
-        mKeyDerivationParameters = Preconditions.checkNotNull(keyDerivationParameters);
-        mSecret = Preconditions.checkNotNull(secret);
-    }
-
-    /**
-     * Specifies UX shown to user during recovery.
-     *
-     * @see KeyStore.TYPE_PIN
-     * @see KeyStore.TYPE_PASSWORD
-     * @see KeyStore.TYPE_PATTERN
-     */
-    public @LockScreenUiFormat int getLockScreenUiFormat() {
-        return mLockScreenUiFormat;
-    }
-
-    /**
-     * Specifies function used to derive symmetric key from user input
-     * Format is defined in separate util class.
-     */
-    public @NonNull KeyDerivationParameters getKeyDerivationParameters() {
-        return mKeyDerivationParameters;
-    }
-
-    /**
-     * Secret string derived from user input.
-     */
-    public @NonNull byte[] getSecret() {
-        return mSecret;
-    }
-
-    /**
-     * @see KeyStore.TYPE_LOCKSCREEN
-     * @see KeyStore.TYPE_CUSTOM_PASSWORD
-     */
-    public @UserSecretType int getUserSecretType() {
-        return mUserSecretType;
-    }
-
-    /**
-     * Removes secret from memory than object is no longer used.
-     * Since finalizer call is not reliable, please use @link {#clearSecret} directly.
-     */
-    @Override
-    protected void finalize() throws Throwable {
-        clearSecret();
-        super.finalize();
-    }
-
-    /**
-     * Fills mSecret with zeroes.
-     */
-    public void clearSecret() {
-        Arrays.fill(mSecret, (byte) 0);
-    }
-
-    public static final Parcelable.Creator<KeyStoreRecoveryMetadata> CREATOR =
-            new Parcelable.Creator<KeyStoreRecoveryMetadata>() {
-        public KeyStoreRecoveryMetadata createFromParcel(Parcel in) {
-            return new KeyStoreRecoveryMetadata(in);
-        }
-
-        public KeyStoreRecoveryMetadata[] newArray(int length) {
-            return new KeyStoreRecoveryMetadata[length];
-        }
-    };
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mUserSecretType);
-        out.writeInt(mLockScreenUiFormat);
-        out.writeTypedObject(mKeyDerivationParameters, flags);
-        out.writeByteArray(mSecret);
-    }
-
-    protected KeyStoreRecoveryMetadata(Parcel in) {
-        mUserSecretType = in.readInt();
-        mLockScreenUiFormat = in.readInt();
-        mKeyDerivationParameters = in.readTypedObject(KeyDerivationParameters.CREATOR);
-        mSecret = in.createByteArray();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-}
diff --git a/core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java b/core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java
deleted file mode 100644
index b5ec795..0000000
--- a/core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.recoverablekeystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
-import android.security.KeyStore;
-import android.util.AndroidException;
-
-import com.android.internal.widget.ILockSettings;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * A wrapper around KeyStore which lets key be exported to trusted hardware on server side and
- * recovered later.
- *
- * @hide
- */
-public class RecoverableKeyStoreLoader {
-
-    public static final String PERMISSION_RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
-
-    public static final int NO_ERROR = KeyStore.NO_ERROR;
-    public static final int SYSTEM_ERROR = KeyStore.SYSTEM_ERROR;
-
-    /**
-     * Failed because the loader has not been initialized with a recovery public key yet.
-     */
-    public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20;
-
-    /**
-     * Failed because no snapshot is yet pending to be synced for the user.
-     */
-    public static final int ERROR_NO_SNAPSHOT_PENDING = 21;
-
-    /**
-     * Failed due to an error internal to AndroidKeyStore.
-     */
-    public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22;
-
-    /**
-     * Failed because the user does not have a lock screen set.
-     */
-    public static final int ERROR_INSECURE_USER = 24;
-
-    /**
-     * Failed because of an internal database error.
-     */
-    public static final int ERROR_DATABASE_ERROR = 25;
-
-    /**
-     * Failed because the provided certificate was not a valid X509 certificate.
-     */
-    public static final int ERROR_BAD_X509_CERTIFICATE = 26;
-
-    /**
-     * Should never be thrown - some algorithm that all AOSP implementations must support is
-     * not available.
-     */
-    public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27;
-
-    /**
-     * The caller is attempting to perform an operation that is not yet fully supported in the API.
-     */
-    public static final int ERROR_NOT_YET_SUPPORTED = 28;
-
-    /**
-     * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong,
-     * the data has become corrupted, the data has been tampered with, etc.
-     */
-    public static final int ERROR_DECRYPTION_FAILED = 29;
-
-    /**
-     * Rate limit is enforced to prevent using too many trusted remote devices, since each device
-     * can have its own number of user secret guesses allowed.
-     *
-     * @hide
-     */
-    public static final int ERROR_RATE_LIMIT_EXCEEDED = 30;
-
-    /** Key has been successfully synced. */
-    public static final int RECOVERY_STATUS_SYNCED = 0;
-    /** Waiting for recovery agent to sync the key. */
-    public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1;
-    /** Recovery account is not available. */
-    public static final int RECOVERY_STATUS_MISSING_ACCOUNT = 2;
-    /** Key cannot be synced. */
-    public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3;
-
-    private final ILockSettings mBinder;
-
-    private RecoverableKeyStoreLoader(ILockSettings binder) {
-        mBinder = binder;
-    }
-
-    /** @hide */
-    public static RecoverableKeyStoreLoader getInstance() {
-        ILockSettings lockSettings =
-                ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
-        return new RecoverableKeyStoreLoader(lockSettings);
-    }
-
-    /**
-     * Exceptions returned by {@link RecoverableKeyStoreLoader}.
-     *
-     * @hide
-     */
-    public static class RecoverableKeyStoreLoaderException extends AndroidException {
-        private int mErrorCode;
-
-        /**
-         * Creates new {@link #RecoverableKeyStoreLoaderException} instance from the error code.
-         *
-         * @param errorCode An error code, as listed at the top of this file.
-         * @param message The associated error message.
-         * @hide
-         */
-        public static RecoverableKeyStoreLoaderException fromErrorCode(
-                int errorCode, String message) {
-            return new RecoverableKeyStoreLoaderException(errorCode, message);
-        }
-
-        /**
-         * Creates new {@link #RecoverableKeyStoreLoaderException} from {@link
-         * ServiceSpecificException}.
-         *
-         * @param e exception thrown on service side.
-         * @hide
-         */
-        static RecoverableKeyStoreLoaderException fromServiceSpecificException(
-                ServiceSpecificException e) throws RecoverableKeyStoreLoaderException {
-            throw RecoverableKeyStoreLoaderException.fromErrorCode(e.errorCode, e.getMessage());
-        }
-
-        private RecoverableKeyStoreLoaderException(int errorCode, String message) {
-            super(message);
-            mErrorCode = errorCode;
-        }
-
-        /** Returns errorCode. */
-        public int getErrorCode() {
-            return mErrorCode;
-        }
-    }
-
-    /**
-     * Initializes key recovery service for the calling application. RecoverableKeyStoreLoader
-     * randomly chooses one of the keys from the list and keeps it to use for future key export
-     * operations. Collection of all keys in the list must be signed by the provided {@code
-     * rootCertificateAlias}, which must also be present in the list of root certificates
-     * preinstalled on the device. The random selection allows RecoverableKeyStoreLoader to select
-     * which of a set of remote recovery service devices will be used.
-     *
-     * <p>In addition, RecoverableKeyStoreLoader enforces a delay of three months between
-     * consecutive initialization attempts, to limit the ability of an attacker to often switch
-     * remote recovery devices and significantly increase number of recovery attempts.
-     *
-     * @param rootCertificateAlias alias of a root certificate preinstalled on the device
-     * @param signedPublicKeyList binary blob a list of X509 certificates and signature
-     * @throws RecoverableKeyStoreLoaderException if signature is invalid, or key rotation was rate
-     *     limited.
-     * @hide
-     */
-    public void initRecoveryService(
-            @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Returns data necessary to store all recoverable keys for given account. Key material is
-     * encrypted with user secret and recovery public key.
-     *
-     * @param account specific to Recovery agent.
-     * @return Data necessary to recover keystore.
-     * @hide
-     */
-    public @NonNull KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            KeyStoreRecoveryData recoveryData = mBinder.getRecoveryData(account);
-            return recoveryData;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Sets a listener which notifies recovery agent that new recovery snapshot is available. {@link
-     * #getRecoveryData} can be used to get the snapshot. Note that every recovery agent can have at
-     * most one registered listener at any time.
-     *
-     * @param intent triggered when new snapshot is available. Unregisters listener if the value is
-     *     {@code null}.
-     * @hide
-     */
-    public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            mBinder.setSnapshotCreatedPendingIntent(intent);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Returns a map from recovery agent accounts to corresponding KeyStore recovery snapshot
-     * version. Version zero is used, if no snapshots were created for the account.
-     *
-     * @return Map from recovery agent accounts to snapshot versions.
-     * @see KeyStoreRecoveryData#getSnapshotVersion
-     * @hide
-     */
-    public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions()
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            // IPC doesn't support generic Maps.
-            @SuppressWarnings("unchecked")
-            Map<byte[], Integer> result =
-                    (Map<byte[], Integer>) mBinder.getRecoverySnapshotVersions();
-            return result;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Server parameters used to generate new recovery key blobs. This value will be included in
-     * {@code KeyStoreRecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included
-     * in vaultParams {@link #startRecoverySession}
-     *
-     * @param serverParameters included in recovery key blob.
-     * @see #getRecoveryData
-     * @throws RecoverableKeyStoreLoaderException If parameters rotation is rate limited.
-     * @hide
-     */
-    public void setServerParameters(long serverParameters)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            mBinder.setServerParameters(serverParameters);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Updates recovery status for given keys. It is used to notify keystore that key was
-     * successfully stored on the server or there were an error. Application can check this value
-     * using {@code getRecoveyStatus}.
-     *
-     * @param packageName Application whose recoverable keys' statuses are to be updated.
-     * @param aliases List of application-specific key aliases. If the array is empty, updates the
-     *     status for all existing recoverable keys.
-     * @param status Status specific to recovery agent.
-     */
-    public void setRecoveryStatus(
-            @NonNull String packageName, @Nullable String[] aliases, int status)
-            throws NameNotFoundException, RecoverableKeyStoreLoaderException {
-        try {
-            mBinder.setRecoveryStatus(packageName, aliases, status);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Returns a {@code Map} from Application's KeyStore key aliases to their recovery status.
-     * Negative status values are reserved for recovery agent specific codes. List of common codes:
-     *
-     * <ul>
-     *   <li>{@link #RECOVERY_STATUS_SYNCED}
-     *   <li>{@link #RECOVERY_STATUS_SYNC_IN_PROGRESS}
-     *   <li>{@link #RECOVERY_STATUS_MISSING_ACCOUNT}
-     *   <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE}
-     * </ul>
-     *
-     * @param packageName Application whose recoverable keys' statuses are to be retrieved. if
-     *     {@code null} caller's package will be used.
-     * @return {@code Map} from KeyStore alias to recovery status.
-     * @see #setRecoveryStatus
-     * @hide
-     */
-    public Map<String, Integer> getRecoveryStatus(@Nullable String packageName)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            // IPC doesn't support generic Maps.
-            @SuppressWarnings("unchecked")
-            Map<String, Integer> result =
-                    (Map<String, Integer>)
-                            mBinder.getRecoveryStatus(packageName);
-            return result;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them
-     * is necessary to recover data.
-     *
-     * @param secretTypes {@link KeyStoreRecoveryMetadata#TYPE_LOCKSCREEN} or {@link
-     *     KeyStoreRecoveryMetadata#TYPE_CUSTOM_PASSWORD}
-     */
-    public void setRecoverySecretTypes(
-            @NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] secretTypes)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            mBinder.setRecoverySecretTypes(secretTypes);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Defines a set of secret types used for end-to-end keystore encryption. Knowing all of them is
-     * necessary to generate KeyStoreRecoveryData.
-     *
-     * @return list of recovery secret types
-     * @see KeyStoreRecoveryData
-     */
-    public @NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] getRecoverySecretTypes()
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            return mBinder.getRecoverySecretTypes();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Returns a list of recovery secret types, necessary to create a pending recovery snapshot.
-     * When user enters a secret of a pending type {@link #recoverySecretAvailable} should be
-     * called.
-     *
-     * @return list of recovery secret types
-     */
-    public @NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] getPendingRecoverySecretTypes()
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            return mBinder.getPendingRecoverySecretTypes();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Method notifies KeyStore that a user-generated secret is available. This method generates a
-     * symmetric session key which a trusted remote device can use to return a recovery key. Caller
-     * should use {@link KeyStoreRecoveryMetadata#clearSecret} to override the secret value in
-     * memory.
-     *
-     * @param recoverySecret user generated secret together with parameters necessary to regenerate
-     *     it on a new device.
-     */
-    public void recoverySecretAvailable(@NonNull KeyStoreRecoveryMetadata recoverySecret)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            mBinder.recoverySecretAvailable(recoverySecret);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Initializes recovery session and returns a blob with proof of recovery secrets possession.
-     * The method generates symmetric key for a session, which trusted remote device can use to
-     * return recovery key.
-     *
-     * @param sessionId ID for recovery session.
-     * @param verifierPublicKey Certificate with Public key used to create the recovery blob on the
-     *     source device. Keystore will verify the certificate using root of trust.
-     * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
-     *     Used to limit number of guesses.
-     * @param vaultChallenge Data passed from server for this recovery session and used to prevent
-     *     replay attacks
-     * @param secrets Secrets provided by user, the method only uses type and secret fields.
-     * @return Binary blob with recovery claim. It is encrypted with verifierPublicKey and contains
-     *     a proof of user secrets, session symmetric key and parameters necessary to identify the
-     *     counter with the number of failed recovery attempts.
-     */
-    public @NonNull byte[] startRecoverySession(
-            @NonNull String sessionId,
-            @NonNull byte[] verifierPublicKey,
-            @NonNull byte[] vaultParams,
-            @NonNull byte[] vaultChallenge,
-            @NonNull List<KeyStoreRecoveryMetadata> secrets)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            byte[] recoveryClaim =
-                    mBinder.startRecoverySession(
-                            sessionId,
-                            verifierPublicKey,
-                            vaultParams,
-                            vaultChallenge,
-                            secrets);
-            return recoveryClaim;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Imports keys.
-     *
-     * @param sessionId Id for recovery session, same as in
-     *     {@link #startRecoverySession(String, byte[], byte[], byte[], List)}.
-     * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
-     * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
-     *     and session. KeyStore only uses package names from the application info in {@link
-     *     KeyEntryRecoveryData}. Caller is responsibility to perform certificates check.
-     * @return Map from alias to raw key material.
-     */
-    public Map<String, byte[]> recoverKeys(
-            @NonNull String sessionId,
-            @NonNull byte[] recoveryKeyBlob,
-            @NonNull List<KeyEntryRecoveryData> applicationKeys)
-            throws RecoverableKeyStoreLoaderException {
-        try {
-            return (Map<String, byte[]>) mBinder.recoverKeys(
-                    sessionId, recoveryKeyBlob, applicationKeys);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Generates a key called {@code alias} and loads it into the recoverable key store. Returns the
-     * raw material of the key.
-     *
-     * @throws RecoverableKeyStoreLoaderException if an error occurred generating and storing the
-     *     key.
-     */
-    public byte[] generateAndStoreKey(String alias) throws RecoverableKeyStoreLoaderException {
-        try {
-            return mBinder.generateAndStoreKey(alias);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
-        }
-    }
-}
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/core/java/android/service/euicc/EuiccProfileInfo.aidl
similarity index 81%
copy from telephony/java/android/telephony/data/InterfaceAddress.aidl
copy to core/java/android/service/euicc/EuiccProfileInfo.aidl
index d750363..321021b 100644
--- a/telephony/java/android/telephony/data/InterfaceAddress.aidl
+++ b/core/java/android/service/euicc/EuiccProfileInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -13,8 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.service.euicc;
 
-/** @hide */
-package android.telephony.data;
-
-parcelable InterfaceAddress;
+parcelable EuiccProfileInfo;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 18d4a1e..20cd906 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -890,6 +890,8 @@
                 createLegacyIconExtras(notification);
                 // populate remote views for older clients.
                 maybePopulateRemoteViews(notification);
+                // populate people for older clients.
+                maybePopulatePeople(notification);
             } catch (IllegalArgumentException e) {
                 if (corruptNotifications == null) {
                     corruptNotifications = new ArrayList<>(N);
@@ -1178,6 +1180,25 @@
         }
     }
 
+    /**
+     * Populates remote views for pre-P targeting apps.
+     */
+    private void maybePopulatePeople(Notification notification) {
+        if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P) {
+            ArrayList<Notification.Person> people = notification.extras.getParcelableArrayList(
+                    Notification.EXTRA_PEOPLE_LIST);
+            if (people != null && people.isEmpty()) {
+                int size = people.size();
+                String[] peopleArray = new String[size];
+                for (int i = 0; i < size; i++) {
+                    Notification.Person person = people.get(i);
+                    peopleArray[i] = person.resolveToLegacyUri();
+                }
+                notification.extras.putStringArray(Notification.EXTRA_PEOPLE, peopleArray);
+            }
+        }
+    }
+
     /** @hide */
     protected class NotificationListenerWrapper extends INotificationListener.Stub {
         @Override
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index 14df7cb..220e498 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -32,4 +32,5 @@
     void isEscrowTokenActive(long handle, int userId);
     void removeEscrowToken(long handle, int userId);
     void unlockUserWithToken(long handle, in byte[] token, int userId);
+    void showKeyguardErrorMessage(in CharSequence message);
 }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 4bade9f..40e84b9 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
@@ -37,6 +38,7 @@
 import android.os.UserManager;
 import android.util.Log;
 import android.util.Slog;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
@@ -301,7 +303,7 @@
     public void onDeviceUnlockLockout(long timeoutMs) {
     }
 
-  /**
+    /**
      * Called when an escrow token is added for user userId.
      *
      * @param token the added token
@@ -561,6 +563,31 @@
         }
     }
 
+    /**
+     * Request showing a transient error message on the keyguard.
+     * The message will be visible on the lock screen or always on display if possible but can be
+     * overridden by other keyguard events of higher priority - eg. fingerprint auth error.
+     * Other trust agents may override your message if posted simultaneously.
+     *
+     * @param message Message to show.
+     */
+    public final void showKeyguardErrorMessage(@NonNull CharSequence message) {
+        if (message == null) {
+            throw new IllegalArgumentException("message cannot be null");
+        }
+        synchronized (mLock) {
+            if (mCallback == null) {
+                Slog.w(TAG, "Cannot show message because service is not connected to framework.");
+                throw new IllegalStateException("Trust agent is not connected");
+            }
+            try {
+                mCallback.showKeyguardErrorMessage(message);
+            } catch (RemoteException e) {
+                onError("calling showKeyguardErrorMessage");
+            }
+        }
+    }
+
     @Override
     public final IBinder onBind(Intent intent) {
         if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index bf4b6ac..aa97b2a 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1917,10 +1917,10 @@
 
     private static float measurePara(TextPaint paint, CharSequence text, int start, int end,
             TextDirectionHeuristic textDir) {
-        MeasuredText mt = null;
+        MeasuredParagraph mt = null;
         TextLine tl = TextLine.obtain();
         try {
-            mt = MeasuredText.buildForBidi(text, start, end, textDir, mt);
+            mt = MeasuredParagraph.buildForBidi(text, start, end, textDir, mt);
             final char[] chars = mt.getChars();
             final int len = chars.length;
             final Directions directions = mt.getDirections(0, len);
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
new file mode 100644
index 0000000..c93e036
--- /dev/null
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -0,0 +1,677 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Paint;
+import android.text.AutoGrowArray.ByteArray;
+import android.text.AutoGrowArray.FloatArray;
+import android.text.AutoGrowArray.IntArray;
+import android.text.Layout.Directions;
+import android.text.style.MetricAffectingSpan;
+import android.text.style.ReplacementSpan;
+import android.util.Pools.SynchronizedPool;
+
+import dalvik.annotation.optimization.CriticalNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.util.Arrays;
+
+/**
+ * MeasuredParagraph provides text information for rendering purpose.
+ *
+ * The first motivation of this class is identify the text directions and retrieving individual
+ * character widths. However retrieving character widths is slower than identifying text directions.
+ * Thus, this class provides several builder methods for specific purposes.
+ *
+ * - buildForBidi:
+ *   Compute only text directions.
+ * - buildForMeasurement:
+ *   Compute text direction and all character widths.
+ * - buildForStaticLayout:
+ *   This is bit special. StaticLayout also needs to know text direction and character widths for
+ *   line breaking, but all things are done in native code. Similarly, text measurement is done
+ *   in native code. So instead of storing result to Java array, this keeps the result in native
+ *   code since there is no good reason to move the results to Java layer.
+ *
+ * In addition to the character widths, some additional information is computed for each purposes,
+ * e.g. whole text length for measurement or font metrics for static layout.
+ *
+ * MeasuredParagraph is NOT a thread safe object.
+ * @hide
+ */
+public class MeasuredParagraph {
+    private static final char OBJECT_REPLACEMENT_CHARACTER = '\uFFFC';
+
+    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+            MeasuredParagraph.class.getClassLoader(), nGetReleaseFunc(), 1024);
+
+    private MeasuredParagraph() {}  // Use build static functions instead.
+
+    private static final SynchronizedPool<MeasuredParagraph> sPool = new SynchronizedPool<>(1);
+
+    private static @NonNull MeasuredParagraph obtain() { // Use build static functions instead.
+        final MeasuredParagraph mt = sPool.acquire();
+        return mt != null ? mt : new MeasuredParagraph();
+    }
+
+    /**
+     * Recycle the MeasuredParagraph.
+     *
+     * Do not call any methods after you call this method.
+     */
+    public void recycle() {
+        release();
+        sPool.release(this);
+    }
+
+    // The casted original text.
+    //
+    // This may be null if the passed text is not a Spanned.
+    private @Nullable Spanned mSpanned;
+
+    // The start offset of the target range in the original text (mSpanned);
+    private @IntRange(from = 0) int mTextStart;
+
+    // The length of the target range in the original text.
+    private @IntRange(from = 0) int mTextLength;
+
+    // The copied character buffer for measuring text.
+    //
+    // The length of this array is mTextLength.
+    private @Nullable char[] mCopiedBuffer;
+
+    // The whole paragraph direction.
+    private @Layout.Direction int mParaDir;
+
+    // True if the text is LTR direction and doesn't contain any bidi characters.
+    private boolean mLtrWithoutBidi;
+
+    // The bidi level for individual characters.
+    //
+    // This is empty if mLtrWithoutBidi is true.
+    private @NonNull ByteArray mLevels = new ByteArray();
+
+    // The whole width of the text.
+    // See getWholeWidth comments.
+    private @FloatRange(from = 0.0f) float mWholeWidth;
+
+    // Individual characters' widths.
+    // See getWidths comments.
+    private @Nullable FloatArray mWidths = new FloatArray();
+
+    // The span end positions.
+    // See getSpanEndCache comments.
+    private @Nullable IntArray mSpanEndCache = new IntArray(4);
+
+    // The font metrics.
+    // See getFontMetrics comments.
+    private @Nullable IntArray mFontMetrics = new IntArray(4 * 4);
+
+    // The native MeasuredParagraph.
+    // See getNativePtr comments.
+    // Do not modify these members directly. Use bindNativeObject/unbindNativeObject instead.
+    private /* Maybe Zero */ long mNativePtr = 0;
+    private @Nullable Runnable mNativeObjectCleaner;
+
+    // Associate the native object to this Java object.
+    private void bindNativeObject(/* Non Zero*/ long nativePtr) {
+        mNativePtr = nativePtr;
+        mNativeObjectCleaner = sRegistry.registerNativeAllocation(this, nativePtr);
+    }
+
+    // Decouple the native object from this Java object and release the native object.
+    private void unbindNativeObject() {
+        if (mNativePtr != 0) {
+            mNativeObjectCleaner.run();
+            mNativePtr = 0;
+        }
+    }
+
+    // Following two objects are for avoiding object allocation.
+    private @NonNull TextPaint mCachedPaint = new TextPaint();
+    private @Nullable Paint.FontMetricsInt mCachedFm;
+
+    /**
+     * Releases internal buffers.
+     */
+    public void release() {
+        reset();
+        mLevels.clearWithReleasingLargeArray();
+        mWidths.clearWithReleasingLargeArray();
+        mFontMetrics.clearWithReleasingLargeArray();
+        mSpanEndCache.clearWithReleasingLargeArray();
+    }
+
+    /**
+     * Resets the internal state for starting new text.
+     */
+    private void reset() {
+        mSpanned = null;
+        mCopiedBuffer = null;
+        mWholeWidth = 0;
+        mLevels.clear();
+        mWidths.clear();
+        mFontMetrics.clear();
+        mSpanEndCache.clear();
+        unbindNativeObject();
+    }
+
+    /**
+     * Returns the characters to be measured.
+     *
+     * This is always available.
+     */
+    public @NonNull char[] getChars() {
+        return mCopiedBuffer;
+    }
+
+    /**
+     * Returns the paragraph direction.
+     *
+     * This is always available.
+     */
+    public @Layout.Direction int getParagraphDir() {
+        return mParaDir;
+    }
+
+    /**
+     * Returns the directions.
+     *
+     * This is always available.
+     */
+    public Directions getDirections(@IntRange(from = 0) int start,  // inclusive
+                                    @IntRange(from = 0) int end) {  // exclusive
+        if (mLtrWithoutBidi) {
+            return Layout.DIRS_ALL_LEFT_TO_RIGHT;
+        }
+
+        final int length = end - start;
+        return AndroidBidi.directions(mParaDir, mLevels.getRawArray(), start, mCopiedBuffer, start,
+                length);
+    }
+
+    /**
+     * Returns the whole text width.
+     *
+     * This is available only if the MeasureText is computed with computeForMeasurement.
+     * Returns 0 in other cases.
+     */
+    public @FloatRange(from = 0.0f) float getWholeWidth() {
+        return mWholeWidth;
+    }
+
+    /**
+     * Returns the individual character's width.
+     *
+     * This is available only if the MeasureText is computed with computeForMeasurement.
+     * Returns empty array in other cases.
+     */
+    public @NonNull FloatArray getWidths() {
+        return mWidths;
+    }
+
+    /**
+     * Returns the MetricsAffectingSpan end indices.
+     *
+     * If the input text is not a spanned string, this has one value that is the length of the text.
+     *
+     * This is available only if the MeasureText is computed with computeForStaticLayout.
+     * Returns empty array in other cases.
+     */
+    public @NonNull IntArray getSpanEndCache() {
+        return mSpanEndCache;
+    }
+
+    /**
+     * Returns the int array which holds FontMetrics.
+     *
+     * This array holds the repeat of top, bottom, ascent, descent of font metrics value.
+     *
+     * This is available only if the MeasureText is computed with computeForStaticLayout.
+     * Returns empty array in other cases.
+     */
+    public @NonNull IntArray getFontMetrics() {
+        return mFontMetrics;
+    }
+
+    /**
+     * Returns the native ptr of the MeasuredParagraph.
+     *
+     * This is available only if the MeasureText is computed with computeForStaticLayout.
+     * Returns 0 in other cases.
+     */
+    public /* Maybe Zero */ long getNativePtr() {
+        return mNativePtr;
+    }
+
+    /**
+     * Generates new MeasuredParagraph for Bidi computation.
+     *
+     * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+     * result to recycle and returns recycle.
+     *
+     * @param text the character sequence to be measured
+     * @param start the inclusive start offset of the target region in the text
+     * @param end the exclusive end offset of the target region in the text
+     * @param textDir the text direction
+     * @param recycle pass existing MeasuredParagraph if you want to recycle it.
+     *
+     * @return measured text
+     */
+    public static @NonNull MeasuredParagraph buildForBidi(@NonNull CharSequence text,
+                                                     @IntRange(from = 0) int start,
+                                                     @IntRange(from = 0) int end,
+                                                     @NonNull TextDirectionHeuristic textDir,
+                                                     @Nullable MeasuredParagraph recycle) {
+        final MeasuredParagraph mt = recycle == null ? obtain() : recycle;
+        mt.resetAndAnalyzeBidi(text, start, end, textDir);
+        return mt;
+    }
+
+    /**
+     * Generates new MeasuredParagraph for measuring texts.
+     *
+     * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+     * result to recycle and returns recycle.
+     *
+     * @param paint the paint to be used for rendering the text.
+     * @param text the character sequence to be measured
+     * @param start the inclusive start offset of the target region in the text
+     * @param end the exclusive end offset of the target region in the text
+     * @param textDir the text direction
+     * @param recycle pass existing MeasuredParagraph if you want to recycle it.
+     *
+     * @return measured text
+     */
+    public static @NonNull MeasuredParagraph buildForMeasurement(@NonNull TextPaint paint,
+                                                            @NonNull CharSequence text,
+                                                            @IntRange(from = 0) int start,
+                                                            @IntRange(from = 0) int end,
+                                                            @NonNull TextDirectionHeuristic textDir,
+                                                            @Nullable MeasuredParagraph recycle) {
+        final MeasuredParagraph mt = recycle == null ? obtain() : recycle;
+        mt.resetAndAnalyzeBidi(text, start, end, textDir);
+
+        mt.mWidths.resize(mt.mTextLength);
+        if (mt.mTextLength == 0) {
+            return mt;
+        }
+
+        if (mt.mSpanned == null) {
+            // No style change by MetricsAffectingSpan. Just measure all text.
+            mt.applyMetricsAffectingSpan(
+                    paint, null /* spans */, start, end, 0 /* native static layout ptr */);
+        } else {
+            // There may be a MetricsAffectingSpan. Split into span transitions and apply styles.
+            int spanEnd;
+            for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
+                spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, MetricAffectingSpan.class);
+                MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
+                        MetricAffectingSpan.class);
+                spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class);
+                mt.applyMetricsAffectingSpan(
+                        paint, spans, spanStart, spanEnd, 0 /* native static layout ptr */);
+            }
+        }
+        return mt;
+    }
+
+    /**
+     * Generates new MeasuredParagraph for StaticLayout.
+     *
+     * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+     * result to recycle and returns recycle.
+     *
+     * @param paint the paint to be used for rendering the text.
+     * @param text the character sequence to be measured
+     * @param start the inclusive start offset of the target region in the text
+     * @param end the exclusive end offset of the target region in the text
+     * @param textDir the text direction
+     * @param recycle pass existing MeasuredParagraph if you want to recycle it.
+     *
+     * @return measured text
+     */
+    public static @NonNull MeasuredParagraph buildForStaticLayout(
+            @NonNull TextPaint paint,
+            @NonNull CharSequence text,
+            @IntRange(from = 0) int start,
+            @IntRange(from = 0) int end,
+            @NonNull TextDirectionHeuristic textDir,
+            @Nullable MeasuredParagraph recycle) {
+        final MeasuredParagraph mt = recycle == null ? obtain() : recycle;
+        mt.resetAndAnalyzeBidi(text, start, end, textDir);
+        if (mt.mTextLength == 0) {
+            // Need to build empty native measured text for StaticLayout.
+            // TODO: Stop creating empty measured text for empty lines.
+            long nativeBuilderPtr = nInitBuilder();
+            try {
+                mt.bindNativeObject(
+                        nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer));
+            } finally {
+                nFreeBuilder(nativeBuilderPtr);
+            }
+            return mt;
+        }
+
+        long nativeBuilderPtr = nInitBuilder();
+        try {
+            if (mt.mSpanned == null) {
+                // No style change by MetricsAffectingSpan. Just measure all text.
+                mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, nativeBuilderPtr);
+                mt.mSpanEndCache.append(end);
+            } else {
+                // There may be a MetricsAffectingSpan. Split into span transitions and apply
+                // styles.
+                int spanEnd;
+                for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
+                    spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
+                                                             MetricAffectingSpan.class);
+                    MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
+                            MetricAffectingSpan.class);
+                    spans = TextUtils.removeEmptySpans(spans, mt.mSpanned,
+                                                       MetricAffectingSpan.class);
+                    mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd,
+                                                 nativeBuilderPtr);
+                    mt.mSpanEndCache.append(spanEnd);
+                }
+            }
+            mt.bindNativeObject(nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer));
+        } finally {
+            nFreeBuilder(nativeBuilderPtr);
+        }
+
+        return mt;
+    }
+
+    /**
+     * Reset internal state and analyzes text for bidirectional runs.
+     *
+     * @param text the character sequence to be measured
+     * @param start the inclusive start offset of the target region in the text
+     * @param end the exclusive end offset of the target region in the text
+     * @param textDir the text direction
+     */
+    private void resetAndAnalyzeBidi(@NonNull CharSequence text,
+                                     @IntRange(from = 0) int start,  // inclusive
+                                     @IntRange(from = 0) int end,  // exclusive
+                                     @NonNull TextDirectionHeuristic textDir) {
+        reset();
+        mSpanned = text instanceof Spanned ? (Spanned) text : null;
+        mTextStart = start;
+        mTextLength = end - start;
+
+        if (mCopiedBuffer == null || mCopiedBuffer.length != mTextLength) {
+            mCopiedBuffer = new char[mTextLength];
+        }
+        TextUtils.getChars(text, start, end, mCopiedBuffer, 0);
+
+        // Replace characters associated with ReplacementSpan to U+FFFC.
+        if (mSpanned != null) {
+            ReplacementSpan[] spans = mSpanned.getSpans(start, end, ReplacementSpan.class);
+
+            for (int i = 0; i < spans.length; i++) {
+                int startInPara = mSpanned.getSpanStart(spans[i]) - start;
+                int endInPara = mSpanned.getSpanEnd(spans[i]) - start;
+                // The span interval may be larger and must be restricted to [start, end)
+                if (startInPara < 0) startInPara = 0;
+                if (endInPara > mTextLength) endInPara = mTextLength;
+                Arrays.fill(mCopiedBuffer, startInPara, endInPara, OBJECT_REPLACEMENT_CHARACTER);
+            }
+        }
+
+        if ((textDir == TextDirectionHeuristics.LTR
+                || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR
+                || textDir == TextDirectionHeuristics.ANYRTL_LTR)
+                && TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) {
+            mLevels.clear();
+            mParaDir = Layout.DIR_LEFT_TO_RIGHT;
+            mLtrWithoutBidi = true;
+        } else {
+            final int bidiRequest;
+            if (textDir == TextDirectionHeuristics.LTR) {
+                bidiRequest = Layout.DIR_REQUEST_LTR;
+            } else if (textDir == TextDirectionHeuristics.RTL) {
+                bidiRequest = Layout.DIR_REQUEST_RTL;
+            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
+                bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR;
+            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
+                bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
+            } else {
+                final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength);
+                bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
+            }
+            mLevels.resize(mTextLength);
+            mParaDir = AndroidBidi.bidi(bidiRequest, mCopiedBuffer, mLevels.getRawArray());
+            mLtrWithoutBidi = false;
+        }
+    }
+
+    private void applyReplacementRun(@NonNull ReplacementSpan replacement,
+                                     @IntRange(from = 0) int start,  // inclusive, in copied buffer
+                                     @IntRange(from = 0) int end,  // exclusive, in copied buffer
+                                     /* Maybe Zero */ long nativeBuilderPtr) {
+        // Use original text. Shouldn't matter.
+        // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for
+        //       backward compatibility? or Should we initialize them for getFontMetricsInt?
+        final float width = replacement.getSize(
+                mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm);
+        if (nativeBuilderPtr == 0) {
+            // Assigns all width to the first character. This is the same behavior as minikin.
+            mWidths.set(start, width);
+            if (end > start + 1) {
+                Arrays.fill(mWidths.getRawArray(), start + 1, end, 0.0f);
+            }
+            mWholeWidth += width;
+        } else {
+            nAddReplacementRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
+                               width);
+        }
+    }
+
+    private void applyStyleRun(@IntRange(from = 0) int start,  // inclusive, in copied buffer
+                               @IntRange(from = 0) int end,  // exclusive, in copied buffer
+                               /* Maybe Zero */ long nativeBuilderPtr) {
+        if (nativeBuilderPtr != 0) {
+            mCachedPaint.getFontMetricsInt(mCachedFm);
+        }
+
+        if (mLtrWithoutBidi) {
+            // If the whole text is LTR direction, just apply whole region.
+            if (nativeBuilderPtr == 0) {
+                mWholeWidth += mCachedPaint.getTextRunAdvances(
+                        mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */,
+                        mWidths.getRawArray(), start);
+            } else {
+                nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
+                        false /* isRtl */);
+            }
+        } else {
+            // If there is multiple bidi levels, split into individual bidi level and apply style.
+            byte level = mLevels.get(start);
+            // Note that the empty text or empty range won't reach this method.
+            // Safe to search from start + 1.
+            for (int levelStart = start, levelEnd = start + 1;; ++levelEnd) {
+                if (levelEnd == end || mLevels.get(levelEnd) != level) {  // transition point
+                    final boolean isRtl = (level & 0x1) != 0;
+                    if (nativeBuilderPtr == 0) {
+                        final int levelLength = levelEnd - levelStart;
+                        mWholeWidth += mCachedPaint.getTextRunAdvances(
+                                mCopiedBuffer, levelStart, levelLength, levelStart, levelLength,
+                                isRtl, mWidths.getRawArray(), levelStart);
+                    } else {
+                        nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), levelStart,
+                                levelEnd, isRtl);
+                    }
+                    if (levelEnd == end) {
+                        break;
+                    }
+                    levelStart = levelEnd;
+                    level = mLevels.get(levelEnd);
+                }
+            }
+        }
+    }
+
+    private void applyMetricsAffectingSpan(
+            @NonNull TextPaint paint,
+            @Nullable MetricAffectingSpan[] spans,
+            @IntRange(from = 0) int start,  // inclusive, in original text buffer
+            @IntRange(from = 0) int end,  // exclusive, in original text buffer
+            /* Maybe Zero */ long nativeBuilderPtr) {
+        mCachedPaint.set(paint);
+        // XXX paint should not have a baseline shift, but...
+        mCachedPaint.baselineShift = 0;
+
+        final boolean needFontMetrics = nativeBuilderPtr != 0;
+
+        if (needFontMetrics && mCachedFm == null) {
+            mCachedFm = new Paint.FontMetricsInt();
+        }
+
+        ReplacementSpan replacement = null;
+        if (spans != null) {
+            for (int i = 0; i < spans.length; i++) {
+                MetricAffectingSpan span = spans[i];
+                if (span instanceof ReplacementSpan) {
+                    // The last ReplacementSpan is effective for backward compatibility reasons.
+                    replacement = (ReplacementSpan) span;
+                } else {
+                    // TODO: No need to call updateMeasureState for ReplacementSpan as well?
+                    span.updateMeasureState(mCachedPaint);
+                }
+            }
+        }
+
+        final int startInCopiedBuffer = start - mTextStart;
+        final int endInCopiedBuffer = end - mTextStart;
+
+        if (replacement != null) {
+            applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer,
+                                nativeBuilderPtr);
+        } else {
+            applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, nativeBuilderPtr);
+        }
+
+        if (needFontMetrics) {
+            if (mCachedPaint.baselineShift < 0) {
+                mCachedFm.ascent += mCachedPaint.baselineShift;
+                mCachedFm.top += mCachedPaint.baselineShift;
+            } else {
+                mCachedFm.descent += mCachedPaint.baselineShift;
+                mCachedFm.bottom += mCachedPaint.baselineShift;
+            }
+
+            mFontMetrics.append(mCachedFm.top);
+            mFontMetrics.append(mCachedFm.bottom);
+            mFontMetrics.append(mCachedFm.ascent);
+            mFontMetrics.append(mCachedFm.descent);
+        }
+    }
+
+    /**
+     * Returns the maximum index that the accumulated width not exceeds the width.
+     *
+     * If forward=false is passed, returns the minimum index from the end instead.
+     *
+     * This only works if the MeasuredParagraph is computed with computeForMeasurement.
+     * Undefined behavior in other case.
+     */
+    @IntRange(from = 0) int breakText(int limit, boolean forwards, float width) {
+        float[] w = mWidths.getRawArray();
+        if (forwards) {
+            int i = 0;
+            while (i < limit) {
+                width -= w[i];
+                if (width < 0.0f) break;
+                i++;
+            }
+            while (i > 0 && mCopiedBuffer[i - 1] == ' ') i--;
+            return i;
+        } else {
+            int i = limit - 1;
+            while (i >= 0) {
+                width -= w[i];
+                if (width < 0.0f) break;
+                i--;
+            }
+            while (i < limit - 1 && (mCopiedBuffer[i + 1] == ' ' || w[i + 1] == 0.0f)) {
+                i++;
+            }
+            return limit - i - 1;
+        }
+    }
+
+    /**
+     * Returns the length of the substring.
+     *
+     * This only works if the MeasuredParagraph is computed with computeForMeasurement.
+     * Undefined behavior in other case.
+     */
+    @FloatRange(from = 0.0f) float measure(int start, int limit) {
+        float width = 0;
+        float[] w = mWidths.getRawArray();
+        for (int i = start; i < limit; ++i) {
+            width += w[i];
+        }
+        return width;
+    }
+
+    private static native /* Non Zero */ long nInitBuilder();
+
+    /**
+     * Apply style to make native measured text.
+     *
+     * @param nativeBuilderPtr The native MeasuredParagraph builder pointer.
+     * @param paintPtr The native paint pointer to be applied.
+     * @param start The start offset in the copied buffer.
+     * @param end The end offset in the copied buffer.
+     * @param isRtl True if the text is RTL.
+     */
+    private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr,
+                                            /* Non Zero */ long paintPtr,
+                                            @IntRange(from = 0) int start,
+                                            @IntRange(from = 0) int end,
+                                            boolean isRtl);
+
+    /**
+     * Apply ReplacementRun to make native measured text.
+     *
+     * @param nativeBuilderPtr The native MeasuredParagraph builder pointer.
+     * @param paintPtr The native paint pointer to be applied.
+     * @param start The start offset in the copied buffer.
+     * @param end The end offset in the copied buffer.
+     * @param width The width of the replacement.
+     */
+    private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr,
+                                                  /* Non Zero */ long paintPtr,
+                                                  @IntRange(from = 0) int start,
+                                                  @IntRange(from = 0) int end,
+                                                  @FloatRange(from = 0) float width);
+
+    private static native long nBuildNativeMeasuredParagraph(/* Non Zero */ long nativeBuilderPtr,
+                                                 @NonNull char[] text);
+
+    private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);
+
+    @CriticalNative
+    private static native /* Non Zero */ long nGetReleaseFunc();
+}
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 14d6f9e..2c30360 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -16,661 +16,255 @@
 
 package android.text;
 
-import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.Paint;
-import android.text.AutoGrowArray.ByteArray;
-import android.text.AutoGrowArray.FloatArray;
-import android.text.AutoGrowArray.IntArray;
-import android.text.Layout.Directions;
-import android.text.style.MetricAffectingSpan;
-import android.text.style.ReplacementSpan;
-import android.util.Pools.SynchronizedPool;
+import android.util.IntArray;
 
-import dalvik.annotation.optimization.CriticalNative;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
 
-import libcore.util.NativeAllocationRegistry;
-
-import java.util.Arrays;
+import java.util.ArrayList;
 
 /**
- * MeasuredText provides text information for rendering purpose.
- *
- * The first motivation of this class is identify the text directions and retrieving individual
- * character widths. However retrieving character widths is slower than identifying text directions.
- * Thus, this class provides several builder methods for specific purposes.
- *
- * - buildForBidi:
- *   Compute only text directions.
- * - buildForMeasurement:
- *   Compute text direction and all character widths.
- * - buildForStaticLayout:
- *   This is bit special. StaticLayout also needs to know text direction and character widths for
- *   line breaking, but all things are done in native code. Similarly, text measurement is done
- *   in native code. So instead of storing result to Java array, this keeps the result in native
- *   code since there is no good reason to move the results to Java layer.
- *
- * In addition to the character widths, some additional information is computed for each purposes,
- * e.g. whole text length for measurement or font metrics for static layout.
- *
- * MeasuredText is NOT a thread safe object.
- * @hide
+ * A text which has already been measured.
  */
-public class MeasuredText {
-    private static final char OBJECT_REPLACEMENT_CHARACTER = '\uFFFC';
+public class MeasuredText implements Spanned {
+    private static final char LINE_FEED = '\n';
 
-    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-            MeasuredText.class.getClassLoader(), nGetReleaseFunc(), 1024);
+    // The original text.
+    private final @NonNull CharSequence mText;
 
-    private MeasuredText() {}  // Use build static functions instead.
+    // The inclusive start offset of the measuring target.
+    private final @IntRange(from = 0) int mStart;
 
-    private static final SynchronizedPool<MeasuredText> sPool = new SynchronizedPool<>(1);
+    // The exclusive end offset of the measuring target.
+    private final @IntRange(from = 0) int mEnd;
 
-    private static @NonNull MeasuredText obtain() { // Use build static functions instead.
-        final MeasuredText mt = sPool.acquire();
-        return mt != null ? mt : new MeasuredText();
+    // The TextPaint used for measurement.
+    private final @NonNull TextPaint mPaint;
+
+    // The requested text direction.
+    private final @NonNull TextDirectionHeuristic mTextDir;
+
+    // The measured paragraph texts.
+    private final @NonNull MeasuredParagraph[] mMeasuredParagraphs;
+
+    // The sorted paragraph end offsets.
+    private final @NonNull int[] mParagraphBreakPoints;
+
+    /**
+     * Build MeasuredText from the text.
+     *
+     * @param text The text to be measured.
+     * @param paint The paint to be used for drawing.
+     * @param textDir The text direction.
+     * @return The measured text.
+     */
+    public static @NonNull MeasuredText build(@NonNull CharSequence text,
+                                              @NonNull TextPaint paint,
+                                              @NonNull TextDirectionHeuristic textDir) {
+        return MeasuredText.build(text, paint, textDir, 0, text.length());
     }
 
     /**
-     * Recycle the MeasuredText.
+     * Build MeasuredText from the specific range of the text..
      *
-     * Do not call any methods after you call this method.
+     * @param text The text to be measured.
+     * @param paint The paint to be used for drawing.
+     * @param textDir The text direction.
+     * @param start The inclusive start offset of the text.
+     * @param end The exclusive start offset of the text.
+     * @return The measured text.
      */
-    public void recycle() {
-        release();
-        sPool.release(this);
+    public static @NonNull MeasuredText build(@NonNull CharSequence text,
+                                              @NonNull TextPaint paint,
+                                              @NonNull TextDirectionHeuristic textDir,
+                                              @IntRange(from = 0) int start,
+                                              @IntRange(from = 0) int end) {
+        Preconditions.checkNotNull(text);
+        Preconditions.checkNotNull(paint);
+        Preconditions.checkNotNull(textDir);
+        Preconditions.checkArgumentInRange(start, 0, text.length(), "start");
+        Preconditions.checkArgumentInRange(end, 0, text.length(), "end");
+
+        final IntArray paragraphEnds = new IntArray();
+        final ArrayList<MeasuredParagraph> measuredTexts = new ArrayList<>();
+
+        int paraEnd = 0;
+        for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
+            paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
+            if (paraEnd < 0) {
+                // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph end.
+                paraEnd = end;
+            } else {
+                paraEnd++;  // Includes LINE_FEED(U+000A) to the prev paragraph.
+            }
+
+            paragraphEnds.add(paraEnd);
+            measuredTexts.add(MeasuredParagraph.buildForStaticLayout(
+                    paint, text, paraStart, paraEnd, textDir, null /* no recycle */));
+        }
+
+        return new MeasuredText(text, start, end, paint, textDir,
+                                measuredTexts.toArray(new MeasuredParagraph[measuredTexts.size()]),
+                                paragraphEnds.toArray());
     }
 
-    // The casted original text.
+    // Use MeasuredText.build instead.
+    private MeasuredText(@NonNull CharSequence text,
+                         @IntRange(from = 0) int start,
+                         @IntRange(from = 0) int end,
+                         @NonNull TextPaint paint,
+                         @NonNull TextDirectionHeuristic textDir,
+                         @NonNull MeasuredParagraph[] measuredTexts,
+                         @NonNull int[] paragraphBreakPoints) {
+        mText = text;
+        mStart = start;
+        mEnd = end;
+        mPaint = paint;
+        mMeasuredParagraphs = measuredTexts;
+        mParagraphBreakPoints = paragraphBreakPoints;
+        mTextDir = textDir;
+    }
+
+    /**
+     * Return the underlying text.
+     */
+    public @NonNull CharSequence getText() {
+        return mText;
+    }
+
+    /**
+     * Returns the inclusive start offset of measured region.
+     */
+    public @IntRange(from = 0) int getStart() {
+        return mStart;
+    }
+
+    /**
+     * Returns the exclusive end offset of measured region.
+     */
+    public @IntRange(from = 0) int getEnd() {
+        return mEnd;
+    }
+
+    /**
+     * Returns the text direction associated with char sequence.
+     */
+    public @NonNull TextDirectionHeuristic getTextDir() {
+        return mTextDir;
+    }
+
+    /**
+     * Returns the paint used to measure this text.
+     */
+    public @NonNull TextPaint getPaint() {
+        return mPaint;
+    }
+
+    /**
+     * Returns the length of the paragraph of this text.
+     */
+    public @IntRange(from = 0) int getParagraphCount() {
+        return mParagraphBreakPoints.length;
+    }
+
+    /**
+     * Returns the paragraph start offset of the text.
+     */
+    public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) {
+        Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
+        return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1];
+    }
+
+    /**
+     * Returns the paragraph end offset of the text.
+     */
+    public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) {
+        Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
+        return mParagraphBreakPoints[paraIndex];
+    }
+
+    /** @hide */
+    public @NonNull MeasuredParagraph getMeasuredParagraph(@IntRange(from = 0) int paraIndex) {
+        return mMeasuredParagraphs[paraIndex];
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Spanned overrides
     //
-    // This may be null if the passed text is not a Spanned.
-    private @Nullable Spanned mSpanned;
+    // Just proxy for underlying mText if appropriate.
 
-    // The start offset of the target range in the original text (mSpanned);
-    private @IntRange(from = 0) int mTextStart;
+    @Override
+    public <T> T[] getSpans(int start, int end, Class<T> type) {
+        if (mText instanceof Spanned) {
+            return ((Spanned) mText).getSpans(start, end, type);
+        } else {
+            return ArrayUtils.emptyArray(type);
+        }
+    }
 
-    // The length of the target range in the original text.
-    private @IntRange(from = 0) int mTextLength;
+    @Override
+    public int getSpanStart(Object tag) {
+        if (mText instanceof Spanned) {
+            return ((Spanned) mText).getSpanStart(tag);
+        } else {
+            return -1;
+        }
+    }
 
-    // The copied character buffer for measuring text.
+    @Override
+    public int getSpanEnd(Object tag) {
+        if (mText instanceof Spanned) {
+            return ((Spanned) mText).getSpanEnd(tag);
+        } else {
+            return -1;
+        }
+    }
+
+    @Override
+    public int getSpanFlags(Object tag) {
+        if (mText instanceof Spanned) {
+            return ((Spanned) mText).getSpanFlags(tag);
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public int nextSpanTransition(int start, int limit, Class type) {
+        if (mText instanceof Spanned) {
+            return ((Spanned) mText).nextSpanTransition(start, limit, type);
+        } else {
+            return mText.length();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // CharSequence overrides.
     //
-    // The length of this array is mTextLength.
-    private @Nullable char[] mCopiedBuffer;
+    // Just proxy for underlying mText.
 
-    // The whole paragraph direction.
-    private @Layout.Direction int mParaDir;
-
-    // True if the text is LTR direction and doesn't contain any bidi characters.
-    private boolean mLtrWithoutBidi;
-
-    // The bidi level for individual characters.
-    //
-    // This is empty if mLtrWithoutBidi is true.
-    private @NonNull ByteArray mLevels = new ByteArray();
-
-    // The whole width of the text.
-    // See getWholeWidth comments.
-    private @FloatRange(from = 0.0f) float mWholeWidth;
-
-    // Individual characters' widths.
-    // See getWidths comments.
-    private @Nullable FloatArray mWidths = new FloatArray();
-
-    // The span end positions.
-    // See getSpanEndCache comments.
-    private @Nullable IntArray mSpanEndCache = new IntArray(4);
-
-    // The font metrics.
-    // See getFontMetrics comments.
-    private @Nullable IntArray mFontMetrics = new IntArray(4 * 4);
-
-    // The native MeasuredText.
-    // See getNativePtr comments.
-    // Do not modify these members directly. Use bindNativeObject/unbindNativeObject instead.
-    private /* Maybe Zero */ long mNativePtr = 0;
-    private @Nullable Runnable mNativeObjectCleaner;
-
-    // Associate the native object to this Java object.
-    private void bindNativeObject(/* Non Zero*/ long nativePtr) {
-        mNativePtr = nativePtr;
-        mNativeObjectCleaner = sRegistry.registerNativeAllocation(this, nativePtr);
+    @Override
+    public int length() {
+        return mText.length();
     }
 
-    // Decouple the native object from this Java object and release the native object.
-    private void unbindNativeObject() {
-        if (mNativePtr != 0) {
-            mNativeObjectCleaner.run();
-            mNativePtr = 0;
-        }
+    @Override
+    public char charAt(int index) {
+        // TODO: Should this be index + mStart ?
+        return mText.charAt(index);
     }
 
-    // Following two objects are for avoiding object allocation.
-    private @NonNull TextPaint mCachedPaint = new TextPaint();
-    private @Nullable Paint.FontMetricsInt mCachedFm;
-
-    /**
-     * Releases internal buffers.
-     */
-    public void release() {
-        reset();
-        mLevels.clearWithReleasingLargeArray();
-        mWidths.clearWithReleasingLargeArray();
-        mFontMetrics.clearWithReleasingLargeArray();
-        mSpanEndCache.clearWithReleasingLargeArray();
+    @Override
+    public CharSequence subSequence(int start, int end) {
+        // TODO: return MeasuredText.
+        // TODO: Should this be index + mStart, end + mStart ?
+        return mText.subSequence(start, end);
     }
 
-    /**
-     * Resets the internal state for starting new text.
-     */
-    private void reset() {
-        mSpanned = null;
-        mCopiedBuffer = null;
-        mWholeWidth = 0;
-        mLevels.clear();
-        mWidths.clear();
-        mFontMetrics.clear();
-        mSpanEndCache.clear();
-        unbindNativeObject();
+    @Override
+    public String toString() {
+        return mText.toString();
     }
-
-    /**
-     * Returns the characters to be measured.
-     *
-     * This is always available.
-     */
-    public @NonNull char[] getChars() {
-        return mCopiedBuffer;
-    }
-
-    /**
-     * Returns the paragraph direction.
-     *
-     * This is always available.
-     */
-    public @Layout.Direction int getParagraphDir() {
-        return mParaDir;
-    }
-
-    /**
-     * Returns the directions.
-     *
-     * This is always available.
-     */
-    public Directions getDirections(@IntRange(from = 0) int start,  // inclusive
-                                    @IntRange(from = 0) int end) {  // exclusive
-        if (mLtrWithoutBidi) {
-            return Layout.DIRS_ALL_LEFT_TO_RIGHT;
-        }
-
-        final int length = end - start;
-        return AndroidBidi.directions(mParaDir, mLevels.getRawArray(), start, mCopiedBuffer, start,
-                length);
-    }
-
-    /**
-     * Returns the whole text width.
-     *
-     * This is available only if the MeasureText is computed with computeForMeasurement.
-     * Returns 0 in other cases.
-     */
-    public @FloatRange(from = 0.0f) float getWholeWidth() {
-        return mWholeWidth;
-    }
-
-    /**
-     * Returns the individual character's width.
-     *
-     * This is available only if the MeasureText is computed with computeForMeasurement.
-     * Returns empty array in other cases.
-     */
-    public @NonNull FloatArray getWidths() {
-        return mWidths;
-    }
-
-    /**
-     * Returns the MetricsAffectingSpan end indices.
-     *
-     * If the input text is not a spanned string, this has one value that is the length of the text.
-     *
-     * This is available only if the MeasureText is computed with computeForStaticLayout.
-     * Returns empty array in other cases.
-     */
-    public @NonNull IntArray getSpanEndCache() {
-        return mSpanEndCache;
-    }
-
-    /**
-     * Returns the int array which holds FontMetrics.
-     *
-     * This array holds the repeat of top, bottom, ascent, descent of font metrics value.
-     *
-     * This is available only if the MeasureText is computed with computeForStaticLayout.
-     * Returns empty array in other cases.
-     */
-    public @NonNull IntArray getFontMetrics() {
-        return mFontMetrics;
-    }
-
-    /**
-     * Returns the native ptr of the MeasuredText.
-     *
-     * This is available only if the MeasureText is computed with computeForStaticLayout.
-     * Returns 0 in other cases.
-     */
-    public /* Maybe Zero */ long getNativePtr() {
-        return mNativePtr;
-    }
-
-    /**
-     * Generates new MeasuredText for Bidi computation.
-     *
-     * If recycle is null, this returns new instance. If recycle is not null, this fills computed
-     * result to recycle and returns recycle.
-     *
-     * @param text the character sequence to be measured
-     * @param start the inclusive start offset of the target region in the text
-     * @param end the exclusive end offset of the target region in the text
-     * @param textDir the text direction
-     * @param recycle pass existing MeasuredText if you want to recycle it.
-     *
-     * @return measured text
-     */
-    public static @NonNull MeasuredText buildForBidi(@NonNull CharSequence text,
-                                                     @IntRange(from = 0) int start,
-                                                     @IntRange(from = 0) int end,
-                                                     @NonNull TextDirectionHeuristic textDir,
-                                                     @Nullable MeasuredText recycle) {
-        final MeasuredText mt = recycle == null ? obtain() : recycle;
-        mt.resetAndAnalyzeBidi(text, start, end, textDir);
-        return mt;
-    }
-
-    /**
-     * Generates new MeasuredText for measuring texts.
-     *
-     * If recycle is null, this returns new instance. If recycle is not null, this fills computed
-     * result to recycle and returns recycle.
-     *
-     * @param paint the paint to be used for rendering the text.
-     * @param text the character sequence to be measured
-     * @param start the inclusive start offset of the target region in the text
-     * @param end the exclusive end offset of the target region in the text
-     * @param textDir the text direction
-     * @param recycle pass existing MeasuredText if you want to recycle it.
-     *
-     * @return measured text
-     */
-    public static @NonNull MeasuredText buildForMeasurement(@NonNull TextPaint paint,
-                                                            @NonNull CharSequence text,
-                                                            @IntRange(from = 0) int start,
-                                                            @IntRange(from = 0) int end,
-                                                            @NonNull TextDirectionHeuristic textDir,
-                                                            @Nullable MeasuredText recycle) {
-        final MeasuredText mt = recycle == null ? obtain() : recycle;
-        mt.resetAndAnalyzeBidi(text, start, end, textDir);
-
-        mt.mWidths.resize(mt.mTextLength);
-        if (mt.mTextLength == 0) {
-            return mt;
-        }
-
-        if (mt.mSpanned == null) {
-            // No style change by MetricsAffectingSpan. Just measure all text.
-            mt.applyMetricsAffectingSpan(
-                    paint, null /* spans */, start, end, 0 /* native static layout ptr */);
-        } else {
-            // There may be a MetricsAffectingSpan. Split into span transitions and apply styles.
-            int spanEnd;
-            for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
-                spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, MetricAffectingSpan.class);
-                MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
-                        MetricAffectingSpan.class);
-                spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class);
-                mt.applyMetricsAffectingSpan(
-                        paint, spans, spanStart, spanEnd, 0 /* native static layout ptr */);
-            }
-        }
-        return mt;
-    }
-
-    /**
-     * Generates new MeasuredText for StaticLayout.
-     *
-     * If recycle is null, this returns new instance. If recycle is not null, this fills computed
-     * result to recycle and returns recycle.
-     *
-     * @param paint the paint to be used for rendering the text.
-     * @param text the character sequence to be measured
-     * @param start the inclusive start offset of the target region in the text
-     * @param end the exclusive end offset of the target region in the text
-     * @param textDir the text direction
-     * @param recycle pass existing MeasuredText if you want to recycle it.
-     *
-     * @return measured text
-     */
-    public static @NonNull MeasuredText buildForStaticLayout(
-            @NonNull TextPaint paint,
-            @NonNull CharSequence text,
-            @IntRange(from = 0) int start,
-            @IntRange(from = 0) int end,
-            @NonNull TextDirectionHeuristic textDir,
-            @Nullable MeasuredText recycle) {
-        final MeasuredText mt = recycle == null ? obtain() : recycle;
-        mt.resetAndAnalyzeBidi(text, start, end, textDir);
-        if (mt.mTextLength == 0) {
-            // Need to build empty native measured text for StaticLayout.
-            // TODO: Stop creating empty measured text for empty lines.
-            long nativeBuilderPtr = nInitBuilder();
-            try {
-                mt.bindNativeObject(nBuildNativeMeasuredText(nativeBuilderPtr, mt.mCopiedBuffer));
-            } finally {
-                nFreeBuilder(nativeBuilderPtr);
-            }
-            return mt;
-        }
-
-        long nativeBuilderPtr = nInitBuilder();
-        try {
-            if (mt.mSpanned == null) {
-                // No style change by MetricsAffectingSpan. Just measure all text.
-                mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, nativeBuilderPtr);
-                mt.mSpanEndCache.append(end);
-            } else {
-                // There may be a MetricsAffectingSpan. Split into span transitions and apply
-                // styles.
-                int spanEnd;
-                for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
-                    spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
-                                                             MetricAffectingSpan.class);
-                    MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
-                            MetricAffectingSpan.class);
-                    spans = TextUtils.removeEmptySpans(spans, mt.mSpanned,
-                                                       MetricAffectingSpan.class);
-                    mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd,
-                                                 nativeBuilderPtr);
-                    mt.mSpanEndCache.append(spanEnd);
-                }
-            }
-            mt.bindNativeObject(nBuildNativeMeasuredText(nativeBuilderPtr, mt.mCopiedBuffer));
-        } finally {
-            nFreeBuilder(nativeBuilderPtr);
-        }
-
-        return mt;
-    }
-
-    /**
-     * Reset internal state and analyzes text for bidirectional runs.
-     *
-     * @param text the character sequence to be measured
-     * @param start the inclusive start offset of the target region in the text
-     * @param end the exclusive end offset of the target region in the text
-     * @param textDir the text direction
-     */
-    private void resetAndAnalyzeBidi(@NonNull CharSequence text,
-                                     @IntRange(from = 0) int start,  // inclusive
-                                     @IntRange(from = 0) int end,  // exclusive
-                                     @NonNull TextDirectionHeuristic textDir) {
-        reset();
-        mSpanned = text instanceof Spanned ? (Spanned) text : null;
-        mTextStart = start;
-        mTextLength = end - start;
-
-        if (mCopiedBuffer == null || mCopiedBuffer.length != mTextLength) {
-            mCopiedBuffer = new char[mTextLength];
-        }
-        TextUtils.getChars(text, start, end, mCopiedBuffer, 0);
-
-        // Replace characters associated with ReplacementSpan to U+FFFC.
-        if (mSpanned != null) {
-            ReplacementSpan[] spans = mSpanned.getSpans(start, end, ReplacementSpan.class);
-
-            for (int i = 0; i < spans.length; i++) {
-                int startInPara = mSpanned.getSpanStart(spans[i]) - start;
-                int endInPara = mSpanned.getSpanEnd(spans[i]) - start;
-                // The span interval may be larger and must be restricted to [start, end)
-                if (startInPara < 0) startInPara = 0;
-                if (endInPara > mTextLength) endInPara = mTextLength;
-                Arrays.fill(mCopiedBuffer, startInPara, endInPara, OBJECT_REPLACEMENT_CHARACTER);
-            }
-        }
-
-        if ((textDir == TextDirectionHeuristics.LTR ||
-                textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR ||
-                textDir == TextDirectionHeuristics.ANYRTL_LTR) &&
-                TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) {
-            mLevels.clear();
-            mParaDir = Layout.DIR_LEFT_TO_RIGHT;
-            mLtrWithoutBidi = true;
-        } else {
-            final int bidiRequest;
-            if (textDir == TextDirectionHeuristics.LTR) {
-                bidiRequest = Layout.DIR_REQUEST_LTR;
-            } else if (textDir == TextDirectionHeuristics.RTL) {
-                bidiRequest = Layout.DIR_REQUEST_RTL;
-            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
-                bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR;
-            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
-                bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
-            } else {
-                final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength);
-                bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
-            }
-            mLevels.resize(mTextLength);
-            mParaDir = AndroidBidi.bidi(bidiRequest, mCopiedBuffer, mLevels.getRawArray());
-            mLtrWithoutBidi = false;
-        }
-    }
-
-    private void applyReplacementRun(@NonNull ReplacementSpan replacement,
-                                     @IntRange(from = 0) int start,  // inclusive, in copied buffer
-                                     @IntRange(from = 0) int end,  // exclusive, in copied buffer
-                                     /* Maybe Zero */ long nativeBuilderPtr) {
-        // Use original text. Shouldn't matter.
-        // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for
-        //       backward compatibility? or Should we initialize them for getFontMetricsInt?
-        final float width = replacement.getSize(
-                mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm);
-        if (nativeBuilderPtr == 0) {
-            // Assigns all width to the first character. This is the same behavior as minikin.
-            mWidths.set(start, width);
-            if (end > start + 1) {
-                Arrays.fill(mWidths.getRawArray(), start + 1, end, 0.0f);
-            }
-            mWholeWidth += width;
-        } else {
-            nAddReplacementRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
-                               width);
-        }
-    }
-
-    private void applyStyleRun(@IntRange(from = 0) int start,  // inclusive, in copied buffer
-                               @IntRange(from = 0) int end,  // exclusive, in copied buffer
-                               /* Maybe Zero */ long nativeBuilderPtr) {
-        if (nativeBuilderPtr != 0) {
-            mCachedPaint.getFontMetricsInt(mCachedFm);
-        }
-
-        if (mLtrWithoutBidi) {
-            // If the whole text is LTR direction, just apply whole region.
-            if (nativeBuilderPtr == 0) {
-                mWholeWidth += mCachedPaint.getTextRunAdvances(
-                        mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */,
-                        mWidths.getRawArray(), start);
-            } else {
-                nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
-                        false /* isRtl */);
-            }
-        } else {
-            // If there is multiple bidi levels, split into individual bidi level and apply style.
-            byte level = mLevels.get(start);
-            // Note that the empty text or empty range won't reach this method.
-            // Safe to search from start + 1.
-            for (int levelStart = start, levelEnd = start + 1;; ++levelEnd) {
-                if (levelEnd == end || mLevels.get(levelEnd) != level) {  // transition point
-                    final boolean isRtl = (level & 0x1) != 0;
-                    if (nativeBuilderPtr == 0) {
-                        final int levelLength = levelEnd - levelStart;
-                        mWholeWidth += mCachedPaint.getTextRunAdvances(
-                                mCopiedBuffer, levelStart, levelLength, levelStart, levelLength,
-                                isRtl, mWidths.getRawArray(), levelStart);
-                    } else {
-                        nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), levelStart,
-                                levelEnd, isRtl);
-                    }
-                    if (levelEnd == end) {
-                        break;
-                    }
-                    levelStart = levelEnd;
-                    level = mLevels.get(levelEnd);
-                }
-            }
-        }
-    }
-
-    private void applyMetricsAffectingSpan(
-            @NonNull TextPaint paint,
-            @Nullable MetricAffectingSpan[] spans,
-            @IntRange(from = 0) int start,  // inclusive, in original text buffer
-            @IntRange(from = 0) int end,  // exclusive, in original text buffer
-            /* Maybe Zero */ long nativeBuilderPtr) {
-        mCachedPaint.set(paint);
-        // XXX paint should not have a baseline shift, but...
-        mCachedPaint.baselineShift = 0;
-
-        final boolean needFontMetrics = nativeBuilderPtr != 0;
-
-        if (needFontMetrics && mCachedFm == null) {
-            mCachedFm = new Paint.FontMetricsInt();
-        }
-
-        ReplacementSpan replacement = null;
-        if (spans != null) {
-            for (int i = 0; i < spans.length; i++) {
-                MetricAffectingSpan span = spans[i];
-                if (span instanceof ReplacementSpan) {
-                    // The last ReplacementSpan is effective for backward compatibility reasons.
-                    replacement = (ReplacementSpan) span;
-                } else {
-                    // TODO: No need to call updateMeasureState for ReplacementSpan as well?
-                    span.updateMeasureState(mCachedPaint);
-                }
-            }
-        }
-
-        final int startInCopiedBuffer = start - mTextStart;
-        final int endInCopiedBuffer = end - mTextStart;
-
-        if (replacement != null) {
-            applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer,
-                                nativeBuilderPtr);
-        } else {
-            applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, nativeBuilderPtr);
-        }
-
-        if (needFontMetrics) {
-            if (mCachedPaint.baselineShift < 0) {
-                mCachedFm.ascent += mCachedPaint.baselineShift;
-                mCachedFm.top += mCachedPaint.baselineShift;
-            } else {
-                mCachedFm.descent += mCachedPaint.baselineShift;
-                mCachedFm.bottom += mCachedPaint.baselineShift;
-            }
-
-            mFontMetrics.append(mCachedFm.top);
-            mFontMetrics.append(mCachedFm.bottom);
-            mFontMetrics.append(mCachedFm.ascent);
-            mFontMetrics.append(mCachedFm.descent);
-        }
-    }
-
-    /**
-     * Returns the maximum index that the accumulated width not exceeds the width.
-     *
-     * If forward=false is passed, returns the minimum index from the end instead.
-     *
-     * This only works if the MeasuredText is computed with computeForMeasurement.
-     * Undefined behavior in other case.
-     */
-    @IntRange(from = 0) int breakText(int limit, boolean forwards, float width) {
-        float[] w = mWidths.getRawArray();
-        if (forwards) {
-            int i = 0;
-            while (i < limit) {
-                width -= w[i];
-                if (width < 0.0f) break;
-                i++;
-            }
-            while (i > 0 && mCopiedBuffer[i - 1] == ' ') i--;
-            return i;
-        } else {
-            int i = limit - 1;
-            while (i >= 0) {
-                width -= w[i];
-                if (width < 0.0f) break;
-                i--;
-            }
-            while (i < limit - 1 && (mCopiedBuffer[i + 1] == ' ' || w[i + 1] == 0.0f)) {
-                i++;
-            }
-            return limit - i - 1;
-        }
-    }
-
-    /**
-     * Returns the length of the substring.
-     *
-     * This only works if the MeasuredText is computed with computeForMeasurement.
-     * Undefined behavior in other case.
-     */
-    @FloatRange(from = 0.0f) float measure(int start, int limit) {
-        float width = 0;
-        float[] w = mWidths.getRawArray();
-        for (int i = start; i < limit; ++i) {
-            width += w[i];
-        }
-        return width;
-    }
-
-    private static native /* Non Zero */ long nInitBuilder();
-
-    /**
-     * Apply style to make native measured text.
-     *
-     * @param nativeBuilderPtr The native MeasuredText builder pointer.
-     * @param paintPtr The native paint pointer to be applied.
-     * @param start The start offset in the copied buffer.
-     * @param end The end offset in the copied buffer.
-     * @param isRtl True if the text is RTL.
-     */
-    private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr,
-                                            /* Non Zero */ long paintPtr,
-                                            @IntRange(from = 0) int start,
-                                            @IntRange(from = 0) int end,
-                                            boolean isRtl);
-
-    /**
-     * Apply ReplacementRun to make native measured text.
-     *
-     * @param nativeBuilderPtr The native MeasuredText builder pointer.
-     * @param paintPtr The native paint pointer to be applied.
-     * @param start The start offset in the copied buffer.
-     * @param end The end offset in the copied buffer.
-     * @param width The width of the replacement.
-     */
-    private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr,
-                                                  /* Non Zero */ long paintPtr,
-                                                  @IntRange(from = 0) int start,
-                                                  @IntRange(from = 0) int end,
-                                                  @FloatRange(from = 0) float width);
-
-    private static native long nBuildNativeMeasuredText(/* Non Zero */ long nativeBuilderPtr,
-                                                 @NonNull char[] text);
-
-    private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);
-
-    @CriticalNative
-    private static native /* Non Zero */ long nGetReleaseFunc();
 }
diff --git a/core/java/android/text/PremeasuredText.java b/core/java/android/text/PremeasuredText.java
deleted file mode 100644
index 465314d..0000000
--- a/core/java/android/text/PremeasuredText.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.util.IntArray;
-
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.Preconditions;
-
-import java.util.ArrayList;
-
-/**
- * A text which has already been measured.
- *
- * TODO: Rename to better name? e.g. MeasuredText, FrozenText etc.
- */
-public class PremeasuredText implements Spanned {
-    private static final char LINE_FEED = '\n';
-
-    // The original text.
-    private final @NonNull CharSequence mText;
-
-    // The inclusive start offset of the measuring target.
-    private final @IntRange(from = 0) int mStart;
-
-    // The exclusive end offset of the measuring target.
-    private final @IntRange(from = 0) int mEnd;
-
-    // The TextPaint used for measurement.
-    private final @NonNull TextPaint mPaint;
-
-    // The requested text direction.
-    private final @NonNull TextDirectionHeuristic mTextDir;
-
-    // The measured paragraph texts.
-    private final @NonNull MeasuredText[] mMeasuredTexts;
-
-    // The sorted paragraph end offsets.
-    private final @NonNull int[] mParagraphBreakPoints;
-
-    /**
-     * Build PremeasuredText from the text.
-     *
-     * @param text The text to be measured.
-     * @param paint The paint to be used for drawing.
-     * @param textDir The text direction.
-     * @return The measured text.
-     */
-    public static @NonNull PremeasuredText build(@NonNull CharSequence text,
-                                                 @NonNull TextPaint paint,
-                                                 @NonNull TextDirectionHeuristic textDir) {
-        return PremeasuredText.build(text, paint, textDir, 0, text.length());
-    }
-
-    /**
-     * Build PremeasuredText from the specific range of the text..
-     *
-     * @param text The text to be measured.
-     * @param paint The paint to be used for drawing.
-     * @param textDir The text direction.
-     * @param start The inclusive start offset of the text.
-     * @param end The exclusive start offset of the text.
-     * @return The measured text.
-     */
-    public static @NonNull PremeasuredText build(@NonNull CharSequence text,
-                                                 @NonNull TextPaint paint,
-                                                 @NonNull TextDirectionHeuristic textDir,
-                                                 @IntRange(from = 0) int start,
-                                                 @IntRange(from = 0) int end) {
-        Preconditions.checkNotNull(text);
-        Preconditions.checkNotNull(paint);
-        Preconditions.checkNotNull(textDir);
-        Preconditions.checkArgumentInRange(start, 0, text.length(), "start");
-        Preconditions.checkArgumentInRange(end, 0, text.length(), "end");
-
-        final IntArray paragraphEnds = new IntArray();
-        final ArrayList<MeasuredText> measuredTexts = new ArrayList<>();
-
-        int paraEnd = 0;
-        for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
-            paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
-            if (paraEnd < 0) {
-                // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph end.
-                paraEnd = end;
-            } else {
-                paraEnd++;  // Includes LINE_FEED(U+000A) to the prev paragraph.
-            }
-
-            paragraphEnds.add(paraEnd);
-            measuredTexts.add(MeasuredText.buildForStaticLayout(
-                    paint, text, paraStart, paraEnd, textDir, null /* no recycle */));
-        }
-
-        return new PremeasuredText(text, start, end, paint, textDir,
-                                   measuredTexts.toArray(new MeasuredText[measuredTexts.size()]),
-                                   paragraphEnds.toArray());
-    }
-
-    // Use PremeasuredText.build instead.
-    private PremeasuredText(@NonNull CharSequence text,
-                            @IntRange(from = 0) int start,
-                            @IntRange(from = 0) int end,
-                            @NonNull TextPaint paint,
-                            @NonNull TextDirectionHeuristic textDir,
-                            @NonNull MeasuredText[] measuredTexts,
-                            @NonNull int[] paragraphBreakPoints) {
-        mText = text;
-        mStart = start;
-        mEnd = end;
-        mPaint = paint;
-        mMeasuredTexts = measuredTexts;
-        mParagraphBreakPoints = paragraphBreakPoints;
-        mTextDir = textDir;
-    }
-
-    /**
-     * Return the underlying text.
-     */
-    public @NonNull CharSequence getText() {
-        return mText;
-    }
-
-    /**
-     * Returns the inclusive start offset of measured region.
-     */
-    public @IntRange(from = 0) int getStart() {
-        return mStart;
-    }
-
-    /**
-     * Returns the exclusive end offset of measured region.
-     */
-    public @IntRange(from = 0) int getEnd() {
-        return mEnd;
-    }
-
-    /**
-     * Returns the text direction associated with char sequence.
-     */
-    public @NonNull TextDirectionHeuristic getTextDir() {
-        return mTextDir;
-    }
-
-    /**
-     * Returns the paint used to measure this text.
-     */
-    public @NonNull TextPaint getPaint() {
-        return mPaint;
-    }
-
-    /**
-     * Returns the length of the paragraph of this text.
-     */
-    public @IntRange(from = 0) int getParagraphCount() {
-        return mParagraphBreakPoints.length;
-    }
-
-    /**
-     * Returns the paragraph start offset of the text.
-     */
-    public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) {
-        Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
-        return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1];
-    }
-
-    /**
-     * Returns the paragraph end offset of the text.
-     */
-    public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) {
-        Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
-        return mParagraphBreakPoints[paraIndex];
-    }
-
-    /** @hide */
-    public @NonNull MeasuredText getMeasuredText(@IntRange(from = 0) int paraIndex) {
-        return mMeasuredTexts[paraIndex];
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Spanned overrides
-    //
-    // Just proxy for underlying mText if appropriate.
-
-    @Override
-    public <T> T[] getSpans(int start, int end, Class<T> type) {
-        if (mText instanceof Spanned) {
-            return ((Spanned) mText).getSpans(start, end, type);
-        } else {
-            return ArrayUtils.emptyArray(type);
-        }
-    }
-
-    @Override
-    public int getSpanStart(Object tag) {
-        if (mText instanceof Spanned) {
-            return ((Spanned) mText).getSpanStart(tag);
-        } else {
-            return -1;
-        }
-    }
-
-    @Override
-    public int getSpanEnd(Object tag) {
-        if (mText instanceof Spanned) {
-            return ((Spanned) mText).getSpanEnd(tag);
-        } else {
-            return -1;
-        }
-    }
-
-    @Override
-    public int getSpanFlags(Object tag) {
-        if (mText instanceof Spanned) {
-            return ((Spanned) mText).getSpanFlags(tag);
-        } else {
-            return 0;
-        }
-    }
-
-    @Override
-    public int nextSpanTransition(int start, int limit, Class type) {
-        if (mText instanceof Spanned) {
-            return ((Spanned) mText).nextSpanTransition(start, limit, type);
-        } else {
-            return mText.length();
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // CharSequence overrides.
-    //
-    // Just proxy for underlying mText.
-
-    @Override
-    public int length() {
-        return mText.length();
-    }
-
-    @Override
-    public char charAt(int index) {
-        // TODO: Should this be index + mStart ?
-        return mText.charAt(index);
-    }
-
-    @Override
-    public CharSequence subSequence(int start, int end) {
-        // TODO: return PremeasuredText.
-        // TODO: Should this be index + mStart, end + mStart ?
-        return mText.subSequence(start, end);
-    }
-
-    @Override
-    public String toString() {
-        return mText.toString();
-    }
-}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index d69b119..36bec86 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -55,7 +55,8 @@
      * First, call nInit to setup native line breaker object. Then, for each paragraph, do the
      * following:
      *
-     *   - Create MeasuredText by MeasuredText.buildForStaticLayout which measures in native.
+     *   - Create MeasuredParagraph by MeasuredParagraph.buildForStaticLayout which measures in
+     *     native.
      *   - Run nComputeLineBreaks() to obtain line breaks for the paragraph.
      *
      * After all paragraphs, call finish() to release expensive buffers.
@@ -650,34 +651,34 @@
                 b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
                 indents, mLeftPaddings, mRightPaddings);
 
-        PremeasuredText premeasured = null;
+        MeasuredText measured = null;
         final Spanned spanned;
-        if (source instanceof PremeasuredText) {
-            premeasured = (PremeasuredText) source;
+        if (source instanceof MeasuredText) {
+            measured = (MeasuredText) source;
 
-            final CharSequence original = premeasured.getText();
+            final CharSequence original = measured.getText();
             spanned = (original instanceof Spanned) ? (Spanned) original : null;
 
-            if (bufStart != premeasured.getStart() || bufEnd != premeasured.getEnd()) {
+            if (bufStart != measured.getStart() || bufEnd != measured.getEnd()) {
                 // The buffer position has changed. Re-measure here.
-                premeasured = PremeasuredText.build(original, paint, textDir, bufStart, bufEnd);
+                measured = MeasuredText.build(original, paint, textDir, bufStart, bufEnd);
             } else {
-                // We can use premeasured information.
+                // We can use measured information.
 
-                // Overwrite with the one when premeasured.
+                // Overwrite with the one when emeasured.
                 // TODO: Give an option for developer not to overwrite and measure again here?
-                textDir = premeasured.getTextDir();
-                paint = premeasured.getPaint();
+                textDir = measured.getTextDir();
+                paint = measured.getPaint();
             }
         } else {
-            premeasured = PremeasuredText.build(source, paint, textDir, bufStart, bufEnd);
+            measured = MeasuredText.build(source, paint, textDir, bufStart, bufEnd);
             spanned = (source instanceof Spanned) ? (Spanned) source : null;
         }
 
         try {
-            for (int paraIndex = 0; paraIndex < premeasured.getParagraphCount(); paraIndex++) {
-                final int paraStart = premeasured.getParagraphStart(paraIndex);
-                final int paraEnd = premeasured.getParagraphEnd(paraIndex);
+            for (int paraIndex = 0; paraIndex < measured.getParagraphCount(); paraIndex++) {
+                final int paraStart = measured.getParagraphStart(paraIndex);
+                final int paraEnd = measured.getParagraphEnd(paraIndex);
 
                 int firstWidthLineCount = 1;
                 int firstWidth = outerWidth;
@@ -743,10 +744,10 @@
                     }
                 }
 
-                final MeasuredText measured = premeasured.getMeasuredText(paraIndex);
-                final char[] chs = measured.getChars();
-                final int[] spanEndCache = measured.getSpanEndCache().getRawArray();
-                final int[] fmCache = measured.getFontMetrics().getRawArray();
+                final MeasuredParagraph measuredPara = measured.getMeasuredParagraph(paraIndex);
+                final char[] chs = measuredPara.getChars();
+                final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray();
+                final int[] fmCache = measuredPara.getFontMetrics().getRawArray();
                 // TODO: Stop keeping duplicated width copy in native and Java.
                 widths.resize(chs.length);
 
@@ -759,7 +760,7 @@
 
                         // Inputs
                         chs,
-                        measured.getNativePtr(),
+                        measuredPara.getNativePtr(),
                         paraEnd - paraStart,
                         firstWidth,
                         firstWidthLineCount,
@@ -863,7 +864,7 @@
                         v = out(source, here, endPos,
                                 ascent, descent, fmTop, fmBottom,
                                 v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
-                                flags[breakIndex], needMultiply, measured, bufEnd,
+                                flags[breakIndex], needMultiply, measuredPara, bufEnd,
                                 includepad, trackpad, addLastLineSpacing, chs, widths.getRawArray(),
                                 paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
                                 paint, moreChars);
@@ -894,8 +895,8 @@
 
             if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE)
                     && mLineCount < mMaximumVisibleLineCount) {
-                final MeasuredText measured =
-                        MeasuredText.buildForBidi(source, bufEnd, bufEnd, textDir, null);
+                final MeasuredParagraph measuredPara =
+                        MeasuredParagraph.buildForBidi(source, bufEnd, bufEnd, textDir, null);
                 paint.getFontMetricsInt(fm);
                 v = out(source,
                         bufEnd, bufEnd, fm.ascent, fm.descent,
@@ -903,7 +904,7 @@
                         v,
                         spacingmult, spacingadd, null,
                         null, fm, 0,
-                        needMultiply, measured, bufEnd,
+                        needMultiply, measuredPara, bufEnd,
                         includepad, trackpad, addLastLineSpacing, null,
                         null, bufStart, ellipsize,
                         ellipsizedWidth, 0, paint, false);
@@ -918,7 +919,7 @@
     private int out(final CharSequence text, final int start, final int end, int above, int below,
             int top, int bottom, int v, final float spacingmult, final float spacingadd,
             final LineHeightSpan[] chooseHt, final int[] chooseHtv, final Paint.FontMetricsInt fm,
-            final int flags, final boolean needMultiply, @NonNull final MeasuredText measured,
+            final int flags, final boolean needMultiply, @NonNull final MeasuredParagraph measured,
             final int bufEnd, final boolean includePad, final boolean trackPad,
             final boolean addLastLineLineSpacing, final char[] chs, final float[] widths,
             final int widthStart, final TextUtils.TruncateAt ellipsize, final float ellipsisWidth,
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 9c9fbf2..409e514 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1250,10 +1250,10 @@
             @NonNull String ellipsis) {
 
         final int len = text.length();
-        MeasuredText mt = null;
-        MeasuredText resultMt = null;
+        MeasuredParagraph mt = null;
+        MeasuredParagraph resultMt = null;
         try {
-            mt = MeasuredText.buildForMeasurement(paint, text, 0, text.length(), textDir, mt);
+            mt = MeasuredParagraph.buildForMeasurement(paint, text, 0, text.length(), textDir, mt);
             float width = mt.getWholeWidth();
 
             if (width <= avail) {
@@ -1332,7 +1332,7 @@
                 if (remaining == 0) { // All text is gone.
                     textFits = true;
                 } else {
-                    resultMt = MeasuredText.buildForMeasurement(
+                    resultMt = MeasuredParagraph.buildForMeasurement(
                             paint, result, 0, result.length(), textDir, resultMt);
                     width = resultMt.getWholeWidth();
                     if (width <= avail) {
@@ -1479,11 +1479,11 @@
     public static CharSequence commaEllipsize(CharSequence text, TextPaint p,
          float avail, String oneMore, String more, TextDirectionHeuristic textDir) {
 
-        MeasuredText mt = null;
-        MeasuredText tempMt = null;
+        MeasuredParagraph mt = null;
+        MeasuredParagraph tempMt = null;
         try {
             int len = text.length();
-            mt = MeasuredText.buildForMeasurement(p, text, 0, len, textDir, mt);
+            mt = MeasuredParagraph.buildForMeasurement(p, text, 0, len, textDir, mt);
             final float width = mt.getWholeWidth();
             if (width <= avail) {
                 return text;
@@ -1523,7 +1523,7 @@
                     }
 
                     // XXX this is probably ok, but need to look at it more
-                    tempMt = MeasuredText.buildForMeasurement(
+                    tempMt = MeasuredParagraph.buildForMeasurement(
                             p, format, 0, format.length(), textDir, tempMt);
                     float moreWid = tempMt.getWholeWidth();
 
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 1d5392e..8242156 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -38,12 +38,12 @@
     static {
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("device_info_v2", "true");
-        DEFAULT_FLAGS.put("settings_search_v2", "true");
-        DEFAULT_FLAGS.put("settings_app_info_v2", "false");
+        DEFAULT_FLAGS.put("settings_app_info_v2", "true");
         DEFAULT_FLAGS.put("settings_connected_device_v2", "true");
         DEFAULT_FLAGS.put("settings_battery_v2", "false");
         DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
         DEFAULT_FLAGS.put("settings_security_settings_v2", "true");
+        DEFAULT_FLAGS.put("settings_zone_picker_v2", "false");
     }
 
     /**
diff --git a/core/java/android/util/StatsManager.java b/core/java/android/util/StatsManager.java
index c25b272..e0d085c 100644
--- a/core/java/android/util/StatsManager.java
+++ b/core/java/android/util/StatsManager.java
@@ -42,6 +42,16 @@
     }
 
     /**
+     * Temporary to prevent build failures. Will be deleted.
+     */
+    @RequiresPermission(Manifest.permission.DUMP)
+    public boolean addConfiguration(String configKey, byte[] config, String pkg, String cls) {
+        // To prevent breakages of dependencies on old API.
+
+        return false;
+    }
+
+    /**
      * Clients can send a configuration and simultaneously registers the name of a broadcast
      * receiver that listens for when it should request data.
      *
@@ -70,6 +80,15 @@
     }
 
     /**
+     * Temporary to prevent build failures. Will be deleted.
+     */
+    @RequiresPermission(Manifest.permission.DUMP)
+    public boolean removeConfiguration(String configKey) {
+        // To prevent breakages of old dependencies.
+        return false;
+    }
+
+    /**
      * Remove a configuration from logging.
      *
      * @param configKey Configuration key to remove.
@@ -93,6 +112,16 @@
     }
 
     /**
+     * Temporary to prevent build failures. Will be deleted.
+     */
+    @RequiresPermission(Manifest.permission.DUMP)
+    public byte[] getData(String configKey) {
+        // TODO: remove this and all other methods with String-based config keys.
+        // To prevent build breakages of dependencies.
+        return null;
+    }
+
+    /**
      * Clients can request data with a binder call. This getter is destructive and also clears
      * the retrieved metrics from statsd memory.
      *
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index cc4a0b6..84ae20b 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -18,30 +18,18 @@
 
 import android.os.SystemClock;
 
-import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
 import libcore.util.TimeZoneFinder;
 import libcore.util.ZoneInfoDB;
 
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
 /**
  * A class containing utility methods related to time zones.
  */
 public class TimeUtils {
     /** @hide */ public TimeUtils() {}
-    private static final boolean DBG = false;
-    private static final String TAG = "TimeUtils";
-
-    /** Cached results of getTimeZonesWithUniqueOffsets */
-    private static final Object sLastUniqueLockObj = new Object();
-    private static List<String> sLastUniqueZoneOffsets = null;
-    private static String sLastUniqueCountry = null;
-
     /** {@hide} */
     private static SimpleDateFormat sLoggingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
@@ -76,86 +64,6 @@
     }
 
     /**
-     * Returns an immutable list of unique time zone IDs for the country.
-     *
-     * @param country to find
-     * @return unmodifiable list of unique time zones, maybe empty but never null.
-     * @hide
-     */
-    public static List<String> getTimeZoneIdsWithUniqueOffsets(String country) {
-        synchronized(sLastUniqueLockObj) {
-            if ((country != null) && country.equals(sLastUniqueCountry)) {
-                if (DBG) {
-                    Log.d(TAG, "getTimeZonesWithUniqueOffsets(" +
-                            country + "): return cached version");
-                }
-                return sLastUniqueZoneOffsets;
-            }
-        }
-
-        Collection<android.icu.util.TimeZone> zones = getIcuTimeZones(country);
-        ArrayList<android.icu.util.TimeZone> uniqueTimeZones = new ArrayList<>();
-        for (android.icu.util.TimeZone zone : zones) {
-            // See if we already have this offset,
-            // Using slow but space efficient and these are small.
-            boolean found = false;
-            for (int i = 0; i < uniqueTimeZones.size(); i++) {
-                if (uniqueTimeZones.get(i).getRawOffset() == zone.getRawOffset()) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                if (DBG) {
-                    Log.d(TAG, "getTimeZonesWithUniqueOffsets: add unique offset=" +
-                            zone.getRawOffset() + " zone.getID=" + zone.getID());
-                }
-                uniqueTimeZones.add(zone);
-            }
-        }
-
-        synchronized(sLastUniqueLockObj) {
-            // Cache the last result
-            sLastUniqueZoneOffsets = extractZoneIds(uniqueTimeZones);
-            sLastUniqueCountry = country;
-
-            return sLastUniqueZoneOffsets;
-        }
-    }
-
-    private static List<String> extractZoneIds(List<android.icu.util.TimeZone> timeZones) {
-        List<String> ids = new ArrayList<>(timeZones.size());
-        for (android.icu.util.TimeZone timeZone : timeZones) {
-            ids.add(timeZone.getID());
-        }
-        return Collections.unmodifiableList(ids);
-    }
-
-    /**
-     * Returns an immutable list of frozen ICU time zones for the country.
-     *
-     * @param countryIso is a two character country code.
-     * @return TimeZone list, maybe empty but never null.
-     * @hide
-     */
-    private static List<android.icu.util.TimeZone> getIcuTimeZones(String countryIso) {
-        if (countryIso == null) {
-            if (DBG) Log.d(TAG, "getIcuTimeZones(null): return empty list");
-            return Collections.emptyList();
-        }
-        List<android.icu.util.TimeZone> timeZones =
-                TimeZoneFinder.getInstance().lookupTimeZonesByCountry(countryIso);
-        if (timeZones == null) {
-            if (DBG) {
-                Log.d(TAG, "getIcuTimeZones(" + countryIso
-                        + "): returned null, converting to empty list");
-            }
-            return Collections.emptyList();
-        }
-        return timeZones;
-    }
-
-    /**
      * Returns a String indicating the version of the time zone database currently
      * in use.  The format of the string is dependent on the underlying time zone
      * database implementation, but will typically contain the year in which the database
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 530937e..ce8998f 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -23,6 +23,9 @@
 import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512;
 import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA256;
 import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_DSA_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_ECDSA_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256;
 import static android.util.apk.ApkSigningBlockUtils.compareSignatureAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.getContentDigestAlgorithmJcaDigestAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.getLengthPrefixedSlice;
@@ -35,7 +38,6 @@
 import android.util.Pair;
 
 import java.io.ByteArrayInputStream;
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.BufferUnderflowException;
@@ -139,7 +141,7 @@
     private static X509Certificate[][] verify(RandomAccessFile apk, boolean verifyIntegrity)
             throws SignatureNotFoundException, SecurityException, IOException {
         SignatureInfo signatureInfo = findSignature(apk);
-        return verify(apk.getFD(), signatureInfo, verifyIntegrity);
+        return verify(apk, signatureInfo, verifyIntegrity);
     }
 
     /**
@@ -162,9 +164,9 @@
      *        against the APK file.
      */
     private static X509Certificate[][] verify(
-            FileDescriptor apkFileDescriptor,
+            RandomAccessFile apk,
             SignatureInfo signatureInfo,
-            boolean doVerifyIntegrity) throws SecurityException {
+            boolean doVerifyIntegrity) throws SecurityException, IOException {
         int signerCount = 0;
         Map<Integer, byte[]> contentDigests = new ArrayMap<>();
         List<X509Certificate[]> signerCerts = new ArrayList<>();
@@ -202,13 +204,7 @@
         }
 
         if (doVerifyIntegrity) {
-            ApkSigningBlockUtils.verifyIntegrity(
-                    contentDigests,
-                    apkFileDescriptor,
-                    signatureInfo.apkSigningBlockOffset,
-                    signatureInfo.centralDirOffset,
-                    signatureInfo.eocdOffset,
-                    signatureInfo.eocd);
+            ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo);
         }
 
         return signerCerts.toArray(new X509Certificate[signerCerts.size()][]);
@@ -386,6 +382,7 @@
         }
         return;
     }
+
     private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
         switch (sigAlgorithm) {
             case SIGNATURE_RSA_PSS_WITH_SHA256:
@@ -395,6 +392,9 @@
             case SIGNATURE_ECDSA_WITH_SHA256:
             case SIGNATURE_ECDSA_WITH_SHA512:
             case SIGNATURE_DSA_WITH_SHA256:
+            case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256:
+            case SIGNATURE_VERITY_ECDSA_WITH_SHA256:
+            case SIGNATURE_VERITY_DSA_WITH_SHA256:
                 return true;
             default:
                 return false;
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index e43dee3..c9e67fe 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -23,6 +23,9 @@
 import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512;
 import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA256;
 import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_DSA_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_ECDSA_WITH_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256;
 import static android.util.apk.ApkSigningBlockUtils.compareSignatureAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.getContentDigestAlgorithmJcaDigestAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.getLengthPrefixedSlice;
@@ -36,7 +39,6 @@
 import android.util.Pair;
 
 import java.io.ByteArrayInputStream;
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.BufferUnderflowException;
@@ -136,7 +138,7 @@
     private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity)
             throws SignatureNotFoundException, SecurityException, IOException {
         SignatureInfo signatureInfo = findSignature(apk);
-        return verify(apk.getFD(), signatureInfo, verifyIntegrity);
+        return verify(apk, signatureInfo, verifyIntegrity);
     }
 
     /**
@@ -159,7 +161,7 @@
      *        against the APK file.
      */
     private static VerifiedSigner verify(
-            FileDescriptor apkFileDescriptor,
+            RandomAccessFile apk,
             SignatureInfo signatureInfo,
             boolean doVerifyIntegrity) throws SecurityException {
         int signerCount = 0;
@@ -206,13 +208,7 @@
         }
 
         if (doVerifyIntegrity) {
-            ApkSigningBlockUtils.verifyIntegrity(
-                    contentDigests,
-                    apkFileDescriptor,
-                    signatureInfo.apkSigningBlockOffset,
-                    signatureInfo.centralDirOffset,
-                    signatureInfo.eocdOffset,
-                    signatureInfo.eocd);
+            ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo);
         }
 
         return result;
@@ -512,6 +508,9 @@
             case SIGNATURE_ECDSA_WITH_SHA256:
             case SIGNATURE_ECDSA_WITH_SHA512:
             case SIGNATURE_DSA_WITH_SHA256:
+            case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256:
+            case SIGNATURE_VERITY_ECDSA_WITH_SHA256:
+            case SIGNATURE_VERITY_DSA_WITH_SHA256:
                 return true;
             default:
                 return false;
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 8146729..555c474 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -25,6 +25,7 @@
 
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.Signature;
 import android.os.Trace;
 import android.util.jar.StrictJarFile;
@@ -52,10 +53,6 @@
  */
 public class ApkSignatureVerifier {
 
-    public static final int VERSION_JAR_SIGNATURE_SCHEME = 1;
-    public static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2;
-    public static final int VERSION_APK_SIGNATURE_SCHEME_V3 = 3;
-
     private static final AtomicReference<byte[]> sBuffer = new AtomicReference<>();
 
     /**
@@ -63,10 +60,11 @@
      *
      * @throws PackageParserException if the APK's signature failed to verify.
      */
-    public static Result verify(String apkPath, int minSignatureSchemeVersion)
+    public static PackageParser.SigningDetails verify(String apkPath,
+            @SignatureSchemeVersion int minSignatureSchemeVersion)
             throws PackageParserException {
 
-        if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V3) {
+        if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
             // V3 and before are older than the requested minimum signing version
             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                     "No signature found in package of version " + minSignatureSchemeVersion
@@ -80,10 +78,11 @@
                     ApkSignatureSchemeV3Verifier.verify(apkPath);
             Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
             Signature[] signerSigs = convertToSignatures(signerCerts);
-            return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V3);
+            return new PackageParser.SigningDetails(signerSigs,
+                    SignatureSchemeVersion.SIGNING_BLOCK_V3);
         } catch (SignatureNotFoundException e) {
             // not signed with v2, try older if allowed
-            if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V3) {
+            if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                         "No APK Signature Scheme v3 signature in package " + apkPath, e);
             }
@@ -97,7 +96,7 @@
         }
 
         // redundant, protective version check
-        if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V2) {
+        if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
             // V2 and before are older than the requested minimum signing version
             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                     "No signature found in package of version " + minSignatureSchemeVersion
@@ -110,10 +109,11 @@
             Certificate[][] signerCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
             Signature[] signerSigs = convertToSignatures(signerCerts);
 
-            return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V2);
+            return new PackageParser.SigningDetails(
+                    signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V2);
         } catch (SignatureNotFoundException e) {
             // not signed with v2, try older if allowed
-            if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V2) {
+            if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                         "No APK Signature Scheme v2 signature in package " + apkPath, e);
             }
@@ -127,7 +127,7 @@
         }
 
         // redundant, protective version check
-        if (minSignatureSchemeVersion > VERSION_JAR_SIGNATURE_SCHEME) {
+        if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
             // V1 and is older than the requested minimum signing version
             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                     "No signature found in package of version " + minSignatureSchemeVersion
@@ -145,7 +145,8 @@
      *
      * @throws PackageParserException if there was a problem collecting certificates
      */
-    private static Result verifyV1Signature(String apkPath, boolean verifyFull)
+    private static PackageParser.SigningDetails verifyV1Signature(
+            String apkPath, boolean verifyFull)
             throws PackageParserException {
         StrictJarFile jarFile = null;
 
@@ -211,7 +212,7 @@
                     }
                 }
             }
-            return new Result(lastCerts, lastSigs, VERSION_JAR_SIGNATURE_SCHEME);
+            return new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR);
         } catch (GeneralSecurityException e) {
             throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
                     "Failed to collect certificates from " + apkPath, e);
@@ -289,10 +290,11 @@
      * @throws PackageParserException if the APK's signature failed to verify.
      * or greater is not found, except in the case of no JAR signature.
      */
-    public static Result plsCertsNoVerifyOnlyCerts(String apkPath, int minSignatureSchemeVersion)
+    public static PackageParser.SigningDetails plsCertsNoVerifyOnlyCerts(
+            String apkPath, int minSignatureSchemeVersion)
             throws PackageParserException {
 
-        if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V3) {
+        if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
             // V3 and before are older than the requested minimum signing version
             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                     "No signature found in package of version " + minSignatureSchemeVersion
@@ -306,10 +308,11 @@
                     ApkSignatureSchemeV3Verifier.plsCertsNoVerifyOnlyCerts(apkPath);
             Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
             Signature[] signerSigs = convertToSignatures(signerCerts);
-            return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V3);
+            return new PackageParser.SigningDetails(signerSigs,
+                    SignatureSchemeVersion.SIGNING_BLOCK_V3);
         } catch (SignatureNotFoundException e) {
             // not signed with v2, try older if allowed
-            if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V3) {
+            if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                         "No APK Signature Scheme v3 signature in package " + apkPath, e);
             }
@@ -323,7 +326,7 @@
         }
 
         // redundant, protective version check
-        if (minSignatureSchemeVersion > VERSION_APK_SIGNATURE_SCHEME_V2) {
+        if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
             // V2 and before are older than the requested minimum signing version
             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                     "No signature found in package of version " + minSignatureSchemeVersion
@@ -336,10 +339,11 @@
             Certificate[][] signerCerts =
                     ApkSignatureSchemeV2Verifier.plsCertsNoVerifyOnlyCerts(apkPath);
             Signature[] signerSigs = convertToSignatures(signerCerts);
-            return new Result(signerCerts, signerSigs, VERSION_APK_SIGNATURE_SCHEME_V2);
+            return new PackageParser.SigningDetails(signerSigs,
+                    SignatureSchemeVersion.SIGNING_BLOCK_V2);
         } catch (SignatureNotFoundException e) {
             // not signed with v2, try older if allowed
-            if (minSignatureSchemeVersion >= VERSION_APK_SIGNATURE_SCHEME_V2) {
+            if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                         "No APK Signature Scheme v2 signature in package " + apkPath, e);
             }
@@ -353,7 +357,7 @@
         }
 
         // redundant, protective version check
-        if (minSignatureSchemeVersion > VERSION_JAR_SIGNATURE_SCHEME) {
+        if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
             // V1 and is older than the requested minimum signing version
             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                     "No signature found in package of version " + minSignatureSchemeVersion
@@ -363,19 +367,4 @@
         // v2 didn't work, try jarsigner
         return verifyV1Signature(apkPath, false);
     }
-
-    /**
-     * Result of a successful APK verification operation.
-     */
-    public static class Result {
-        public final Certificate[][] certs;
-        public final Signature[] sigs;
-        public final int signatureSchemeVersion;
-
-        public Result(Certificate[][] certs, Signature[] sigs, int signingVersion) {
-            this.certs = certs;
-            this.sigs = sigs;
-            this.signatureSchemeVersion = signingVersion;
-        }
-    }
 }
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 9279510..9d53847 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -16,6 +16,7 @@
 
 package android.util.apk;
 
+import android.util.ArrayMap;
 import android.util.Pair;
 
 import java.io.FileDescriptor;
@@ -30,6 +31,7 @@
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.MGF1ParameterSpec;
 import java.security.spec.PSSParameterSpec;
+import java.util.Arrays;
 import java.util.Map;
 
 /**
@@ -84,16 +86,41 @@
 
     static void verifyIntegrity(
             Map<Integer, byte[]> expectedDigests,
-            FileDescriptor apkFileDescriptor,
-            long apkSigningBlockOffset,
-            long centralDirOffset,
-            long eocdOffset,
-            ByteBuffer eocdBuf) throws SecurityException {
-
+            RandomAccessFile apk,
+            SignatureInfo signatureInfo) throws SecurityException {
         if (expectedDigests.isEmpty()) {
             throw new SecurityException("No digests provided");
         }
 
+        Map<Integer, byte[]> expected1MbChunkDigests = new ArrayMap<>();
+        if (expectedDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA256)) {
+            expected1MbChunkDigests.put(CONTENT_DIGEST_CHUNKED_SHA256,
+                    expectedDigests.get(CONTENT_DIGEST_CHUNKED_SHA256));
+        }
+        if (expectedDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA512)) {
+            expected1MbChunkDigests.put(CONTENT_DIGEST_CHUNKED_SHA512,
+                    expectedDigests.get(CONTENT_DIGEST_CHUNKED_SHA512));
+        }
+
+        if (expectedDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
+            verifyIntegrityForVerityBasedAlgorithm(
+                    expectedDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256), apk, signatureInfo);
+        } else if (!expected1MbChunkDigests.isEmpty()) {
+            try {
+                verifyIntegrityFor1MbChunkBasedAlgorithm(expected1MbChunkDigests, apk.getFD(),
+                        signatureInfo);
+            } catch (IOException e) {
+                throw new SecurityException("Cannot get FD", e);
+            }
+        } else {
+            throw new SecurityException("No known digest exists for integrity check");
+        }
+    }
+
+    private static void verifyIntegrityFor1MbChunkBasedAlgorithm(
+            Map<Integer, byte[]> expectedDigests,
+            FileDescriptor apkFileDescriptor,
+            SignatureInfo signatureInfo) throws SecurityException {
         // We need to verify the integrity of the following three sections of the file:
         // 1. Everything up to the start of the APK Signing Block.
         // 2. ZIP Central Directory.
@@ -105,16 +132,18 @@
         // APK are already there in the OS's page cache and thus mmap does not use additional
         // physical memory.
         DataSource beforeApkSigningBlock =
-                new MemoryMappedFileDataSource(apkFileDescriptor, 0, apkSigningBlockOffset);
+                new MemoryMappedFileDataSource(apkFileDescriptor, 0,
+                        signatureInfo.apkSigningBlockOffset);
         DataSource centralDir =
                 new MemoryMappedFileDataSource(
-                        apkFileDescriptor, centralDirOffset, eocdOffset - centralDirOffset);
+                        apkFileDescriptor, signatureInfo.centralDirOffset,
+                        signatureInfo.eocdOffset - signatureInfo.centralDirOffset);
 
         // For the purposes of integrity verification, ZIP End of Central Directory's field Start of
         // Central Directory must be considered to point to the offset of the APK Signing Block.
-        eocdBuf = eocdBuf.duplicate();
+        ByteBuffer eocdBuf = signatureInfo.eocd.duplicate();
         eocdBuf.order(ByteOrder.LITTLE_ENDIAN);
-        ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, apkSigningBlockOffset);
+        ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, signatureInfo.apkSigningBlockOffset);
         DataSource eocd = new ByteBufferDataSource(eocdBuf);
 
         int[] digestAlgorithms = new int[expectedDigests.size()];
@@ -126,7 +155,7 @@
         byte[][] actualDigests;
         try {
             actualDigests =
-                    computeContentDigests(
+                    computeContentDigestsPer1MbChunk(
                             digestAlgorithms,
                             new DataSource[] {beforeApkSigningBlock, centralDir, eocd});
         } catch (DigestException e) {
@@ -144,7 +173,7 @@
         }
     }
 
-    private static byte[][] computeContentDigests(
+    private static byte[][] computeContentDigestsPer1MbChunk(
             int[] digestAlgorithms,
             DataSource[] contents) throws DigestException {
         // For each digest algorithm the result is computed as follows:
@@ -256,6 +285,26 @@
         return result;
     }
 
+    private static void verifyIntegrityForVerityBasedAlgorithm(
+            byte[] expectedRootHash,
+            RandomAccessFile apk,
+            SignatureInfo signatureInfo) throws SecurityException {
+        try {
+            ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerity(apk,
+                    signatureInfo, new ByteBufferFactory() {
+                        @Override
+                        public ByteBuffer create(int capacity) {
+                            return ByteBuffer.allocate(capacity);
+                        }
+                    });
+            if (!Arrays.equals(expectedRootHash, verity.rootHash)) {
+                throw new SecurityException("APK verity digest of contents did not verify");
+            }
+        } catch (DigestException | IOException | NoSuchAlgorithmException e) {
+            throw new SecurityException("Error during verification", e);
+        }
+    }
+
     /**
      * Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
      *
@@ -304,9 +353,13 @@
     static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
     static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
     static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
+    static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0401;
+    static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0403;
+    static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0405;
 
     static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
     static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
+    static final int CONTENT_DIGEST_VERITY_CHUNKED_SHA256 = 3;
 
     static int compareSignatureAlgorithm(int sigAlgorithm1, int sigAlgorithm2) {
         int digestAlgorithm1 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm1);
@@ -321,6 +374,7 @@
                     case CONTENT_DIGEST_CHUNKED_SHA256:
                         return 0;
                     case CONTENT_DIGEST_CHUNKED_SHA512:
+                    case CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
                         return -1;
                     default:
                         throw new IllegalArgumentException(
@@ -329,6 +383,7 @@
             case CONTENT_DIGEST_CHUNKED_SHA512:
                 switch (digestAlgorithm2) {
                     case CONTENT_DIGEST_CHUNKED_SHA256:
+                    case CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
                         return 1;
                     case CONTENT_DIGEST_CHUNKED_SHA512:
                         return 0;
@@ -336,6 +391,18 @@
                         throw new IllegalArgumentException(
                                 "Unknown digestAlgorithm2: " + digestAlgorithm2);
                 }
+            case CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
+                switch (digestAlgorithm2) {
+                    case CONTENT_DIGEST_CHUNKED_SHA512:
+                        return -1;
+                    case CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
+                        return 0;
+                    case CONTENT_DIGEST_CHUNKED_SHA256:
+                        return 1;
+                    default:
+                        throw new IllegalArgumentException(
+                                "Unknown digestAlgorithm2: " + digestAlgorithm2);
+                }
             default:
                 throw new IllegalArgumentException("Unknown digestAlgorithm1: " + digestAlgorithm1);
         }
@@ -352,6 +419,10 @@
             case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
             case SIGNATURE_ECDSA_WITH_SHA512:
                 return CONTENT_DIGEST_CHUNKED_SHA512;
+            case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256:
+            case SIGNATURE_VERITY_ECDSA_WITH_SHA256:
+            case SIGNATURE_VERITY_DSA_WITH_SHA256:
+                return CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
             default:
                 throw new IllegalArgumentException(
                         "Unknown signature algorithm: 0x"
@@ -362,6 +433,7 @@
     static String getContentDigestAlgorithmJcaDigestAlgorithm(int digestAlgorithm) {
         switch (digestAlgorithm) {
             case CONTENT_DIGEST_CHUNKED_SHA256:
+            case CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
                 return "SHA-256";
             case CONTENT_DIGEST_CHUNKED_SHA512:
                 return "SHA-512";
@@ -374,6 +446,7 @@
     private static int getContentDigestAlgorithmOutputSizeBytes(int digestAlgorithm) {
         switch (digestAlgorithm) {
             case CONTENT_DIGEST_CHUNKED_SHA256:
+            case CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
                 return 256 / 8;
             case CONTENT_DIGEST_CHUNKED_SHA512:
                 return 512 / 8;
@@ -389,11 +462,14 @@
             case SIGNATURE_RSA_PSS_WITH_SHA512:
             case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
             case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
+            case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256:
                 return "RSA";
             case SIGNATURE_ECDSA_WITH_SHA256:
             case SIGNATURE_ECDSA_WITH_SHA512:
+            case SIGNATURE_VERITY_ECDSA_WITH_SHA256:
                 return "EC";
             case SIGNATURE_DSA_WITH_SHA256:
+            case SIGNATURE_VERITY_DSA_WITH_SHA256:
                 return "DSA";
             default:
                 throw new IllegalArgumentException(
@@ -416,14 +492,17 @@
                         new PSSParameterSpec(
                                 "SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 512 / 8, 1));
             case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+            case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256:
                 return Pair.create("SHA256withRSA", null);
             case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
                 return Pair.create("SHA512withRSA", null);
             case SIGNATURE_ECDSA_WITH_SHA256:
+            case SIGNATURE_VERITY_ECDSA_WITH_SHA256:
                 return Pair.create("SHA256withECDSA", null);
             case SIGNATURE_ECDSA_WITH_SHA512:
                 return Pair.create("SHA512withECDSA", null);
             case SIGNATURE_DSA_WITH_SHA256:
+            case SIGNATURE_VERITY_DSA_WITH_SHA256:
                 return Pair.create("SHA256withDSA", null);
             default:
                 throw new IllegalArgumentException(
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 3dcfd00..1ef5f09 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -153,7 +153,7 @@
     @Override
     public String toString() {
         return "DisplayCutout{insets=" + mSafeInsets
-                + " bounds=" + mBounds
+                + " boundingRect=" + getBoundingRect()
                 + "}";
     }
 
@@ -279,9 +279,7 @@
      * @hide
      */
     public static DisplayCutout fromBoundingPolygon(List<Point> points) {
-        Region bounds = Region.obtain();
         Path path = new Path();
-
         path.reset();
         for (int i = 0; i < points.size(); i++) {
             Point point = points.get(i);
@@ -292,14 +290,24 @@
             }
         }
         path.close();
+        return fromBounds(path);
+    }
 
+    /**
+     * Creates an instance from a bounding {@link Path}.
+     *
+     * @hide
+     */
+    public static DisplayCutout fromBounds(Path path) {
         RectF clipRect = new RectF();
         path.computeBounds(clipRect, false /* unused */);
         Region clipRegion = Region.obtain();
         clipRegion.set((int) clipRect.left, (int) clipRect.top,
                 (int) clipRect.right, (int) clipRect.bottom);
 
+        Region bounds = new Region();
         bounds.setPath(path, clipRegion);
+        clipRegion.recycle();
         return new DisplayCutout(ZERO_RECT, bounds);
     }
 
@@ -329,12 +337,23 @@
 
         @Override
         public void writeToParcel(Parcel out, int flags) {
-            if (mInner == NO_CUTOUT) {
+            writeCutoutToParcel(mInner, out, flags);
+        }
+
+        /**
+         * Writes a DisplayCutout to a {@link Parcel}.
+         *
+         * @see #readCutoutFromParcel(Parcel)
+         */
+        public static void writeCutoutToParcel(DisplayCutout cutout, Parcel out, int flags) {
+            if (cutout == null) {
+                out.writeInt(-1);
+            } else if (cutout == NO_CUTOUT) {
                 out.writeInt(0);
             } else {
                 out.writeInt(1);
-                out.writeTypedObject(mInner.mSafeInsets, flags);
-                out.writeTypedObject(mInner.mBounds, flags);
+                out.writeTypedObject(cutout.mSafeInsets, flags);
+                out.writeTypedObject(cutout.mBounds, flags);
             }
         }
 
@@ -345,13 +364,13 @@
          * Needed for AIDL out parameters.
          */
         public void readFromParcel(Parcel in) {
-            mInner = readCutout(in);
+            mInner = readCutoutFromParcel(in);
         }
 
         public static final Creator<ParcelableWrapper> CREATOR = new Creator<ParcelableWrapper>() {
             @Override
             public ParcelableWrapper createFromParcel(Parcel in) {
-                return new ParcelableWrapper(readCutout(in));
+                return new ParcelableWrapper(readCutoutFromParcel(in));
             }
 
             @Override
@@ -360,8 +379,17 @@
             }
         };
 
-        private static DisplayCutout readCutout(Parcel in) {
-            if (in.readInt() == 0) {
+        /**
+         * Reads a DisplayCutout from a {@link Parcel}.
+         *
+         * @see #writeCutoutToParcel(DisplayCutout, Parcel, int)
+         */
+        public static DisplayCutout readCutoutFromParcel(Parcel in) {
+            int variant = in.readInt();
+            if (variant == -1) {
+                return null;
+            }
+            if (variant == 0) {
                 return NO_CUTOUT;
             }
 
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index b813ddb..37e9815 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -149,6 +149,13 @@
     public int overscanBottom;
 
     /**
+     * The {@link DisplayCutout} if present, otherwise {@code null}.
+     *
+     * @hide
+     */
+    public DisplayCutout displayCutout;
+
+    /**
      * The rotation of the display relative to its natural orientation.
      * May be one of {@link android.view.Surface#ROTATION_0},
      * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
@@ -301,6 +308,7 @@
                 && overscanTop == other.overscanTop
                 && overscanRight == other.overscanRight
                 && overscanBottom == other.overscanBottom
+                && Objects.equal(displayCutout, other.displayCutout)
                 && rotation == other.rotation
                 && modeId == other.modeId
                 && defaultModeId == other.defaultModeId
@@ -342,6 +350,7 @@
         overscanTop = other.overscanTop;
         overscanRight = other.overscanRight;
         overscanBottom = other.overscanBottom;
+        displayCutout = other.displayCutout;
         rotation = other.rotation;
         modeId = other.modeId;
         defaultModeId = other.defaultModeId;
@@ -379,6 +388,7 @@
         overscanTop = source.readInt();
         overscanRight = source.readInt();
         overscanBottom = source.readInt();
+        displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
         rotation = source.readInt();
         modeId = source.readInt();
         defaultModeId = source.readInt();
@@ -425,6 +435,7 @@
         dest.writeInt(overscanTop);
         dest.writeInt(overscanRight);
         dest.writeInt(overscanBottom);
+        DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
         dest.writeInt(rotation);
         dest.writeInt(modeId);
         dest.writeInt(defaultModeId);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9e103a3..bfcf285 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -147,7 +147,7 @@
     void exitKeyguardSecurely(IOnKeyguardExitResult callback);
     boolean isKeyguardLocked();
     boolean isKeyguardSecure();
-    void dismissKeyguard(IKeyguardDismissCallback callback);
+    void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message);
 
     // Requires INTERACT_ACROSS_USERS_FULL permission
     void setSwitchingUser(boolean switching);
@@ -294,6 +294,11 @@
     boolean hasNavigationBar();
 
     /**
+    * Get the position of the nav bar
+    */
+    int getNavBarPosition();
+
+    /**
      * Lock the device immediately with the specified options (can be null).
      */
     void lockNow(in Bundle options);
@@ -396,4 +401,19 @@
      * Return the touch region for the current IME window, or an empty region if there is none.
      */
     Region getCurrentImeTouchRegion();
+
+    /**
+     * Starts a window trace.
+     */
+    void startWindowTrace();
+
+    /**
+     * Stops a window trace.
+     */
+    void stopWindowTrace();
+
+    /**
+     * Returns true if window trace is enabled.
+     */
+    boolean isWindowTraceEnabled();
 }
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index a2147b7..ed2b8b6 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -804,8 +804,7 @@
     public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282;
     /** Key code constant: Consumed by the system for navigation right */
     public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283;
-    /** Key code constant: Show all apps
-     * @hide */
+    /** Key code constant: Show all apps */
     public static final int KEYCODE_ALL_APPS = 284;
 
     private static final int LAST_KEYCODE = KEYCODE_ALL_APPS;
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index ab0b3ee..fbba8ab 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -47,6 +47,7 @@
     private final int mGravity;
     private View mAppName;
     private View mHeaderText;
+    private View mSecondaryHeaderText;
     private OnClickListener mExpandClickListener;
     private HeaderTouchListener mTouchListener = new HeaderTouchListener();
     private ImageView mExpandButton;
@@ -58,7 +59,6 @@
     private boolean mShowExpandButtonAtEnd;
     private boolean mShowWorkBadgeAtEnd;
     private Drawable mBackground;
-    private int mHeaderBackgroundHeight;
     private boolean mEntireHeaderClickable;
     private boolean mExpandOnlyOnButton;
     private boolean mAcceptAllTouches;
@@ -68,7 +68,7 @@
         @Override
         public void getOutline(View view, Outline outline) {
             if (mBackground != null) {
-                outline.setRect(0, 0, getWidth(), mHeaderBackgroundHeight);
+                outline.setRect(0, 0, getWidth(), getHeight());
                 outline.setAlpha(1f);
             }
         }
@@ -91,8 +91,6 @@
         Resources res = getResources();
         mChildMinWidth = res.getDimensionPixelSize(R.dimen.notification_header_shrink_min_width);
         mContentEndMargin = res.getDimensionPixelSize(R.dimen.notification_content_margin_end);
-        mHeaderBackgroundHeight = res.getDimensionPixelSize(
-                R.dimen.notification_header_background_height);
         mEntireHeaderClickable = res.getBoolean(R.bool.config_notificationHeaderClickableForExpand);
 
         int[] attrIds = { android.R.attr.gravity };
@@ -106,6 +104,7 @@
         super.onFinishInflate();
         mAppName = findViewById(com.android.internal.R.id.app_name_text);
         mHeaderText = findViewById(com.android.internal.R.id.header_text);
+        mSecondaryHeaderText = findViewById(com.android.internal.R.id.header_text_secondary);
         mExpandButton = findViewById(com.android.internal.R.id.expand_button);
         mIcon = findViewById(com.android.internal.R.id.icon);
         mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
@@ -137,26 +136,33 @@
         if (totalWidth > givenWidth) {
             int overFlow = totalWidth - givenWidth;
             // We are overflowing, lets shrink the app name first
-            final int appWidth = mAppName.getMeasuredWidth();
-            if (overFlow > 0 && mAppName.getVisibility() != GONE && appWidth > mChildMinWidth) {
-                int newSize = appWidth - Math.min(appWidth - mChildMinWidth, overFlow);
-                int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
-                mAppName.measure(childWidthSpec, wrapContentHeightSpec);
-                overFlow -= appWidth - newSize;
-            }
-            // still overflowing, finaly we shrink the header text
-            if (overFlow > 0 && mHeaderText.getVisibility() != GONE) {
-                // we're still too big
-                final int textWidth = mHeaderText.getMeasuredWidth();
-                int newSize = Math.max(0, textWidth - overFlow);
-                int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
-                mHeaderText.measure(childWidthSpec, wrapContentHeightSpec);
-            }
+            overFlow = shrinkViewForOverflow(wrapContentHeightSpec, overFlow, mAppName,
+                    mChildMinWidth);
+
+            // still overflowing, we shrink the header text
+            overFlow = shrinkViewForOverflow(wrapContentHeightSpec, overFlow, mHeaderText, 0);
+
+            // still overflowing, finally we shrink the secondary header text
+            shrinkViewForOverflow(wrapContentHeightSpec, overFlow, mSecondaryHeaderText,
+                    0);
         }
         mTotalWidth = Math.min(totalWidth, givenWidth);
         setMeasuredDimension(givenWidth, givenHeight);
     }
 
+    private int shrinkViewForOverflow(int heightSpec, int overFlow, View targetView,
+            int minimumWidth) {
+        final int oldWidth = targetView.getMeasuredWidth();
+        if (overFlow > 0 && targetView.getVisibility() != GONE && oldWidth > minimumWidth) {
+            // we're still too big
+            int newSize = Math.max(minimumWidth, oldWidth - overFlow);
+            int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
+            targetView.measure(childWidthSpec, heightSpec);
+            overFlow -= oldWidth - newSize;
+        }
+        return overFlow;
+    }
+
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         int left = getPaddingStart();
@@ -228,7 +234,7 @@
     @Override
     protected void onDraw(Canvas canvas) {
         if (mBackground != null) {
-            mBackground.setBounds(0, 0, getWidth(), mHeaderBackgroundHeight);
+            mBackground.setBounds(0, 0, getWidth(), getHeight());
             mBackground.draw(canvas);
         }
     }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 268e460..bd7f8e5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -16,20 +16,22 @@
 
 package android.view;
 
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
 import static android.graphics.Matrix.MSCALE_X;
 import static android.graphics.Matrix.MSCALE_Y;
 import static android.graphics.Matrix.MSKEW_X;
 import static android.graphics.Matrix.MSKEW_Y;
 import static android.graphics.Matrix.MTRANS_X;
 import static android.graphics.Matrix.MTRANS_Y;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static android.view.SurfaceControlProto.HASH_CODE;
+import static android.view.SurfaceControlProto.NAME;
 
 import android.annotation.Size;
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
-import android.graphics.PixelFormat;
 import android.graphics.Matrix;
+import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -40,11 +42,13 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 import android.view.Surface.OutOfResourcesException;
 
 import com.android.internal.annotations.GuardedBy;
 
 import dalvik.system.CloseGuard;
+
 import libcore.util.NativeAllocationRegistry;
 
 import java.io.Closeable;
@@ -628,6 +632,21 @@
         nativeWriteToParcel(mNativeObject, dest);
     }
 
+    /**
+     * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link
+     * android.view.SurfaceControlProto}.
+     *
+     * @param proto Stream to write the SurfaceControl object to.
+     * @param fieldId Field Id of the SurfaceControl as defined in the parent message.
+     * @hide
+     */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(HASH_CODE, System.identityHashCode(this));
+        proto.write(NAME, mName);
+        proto.end(token);
+    }
+
     public static final Creator<SurfaceControl> CREATOR
             = new Creator<SurfaceControl>() {
         public SurfaceControl createFromParcel(Parcel in) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f62189e..bd3be1b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3226,6 +3226,11 @@
      */
     private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000;
 
+    /**
+     * The last aggregated visibility. Used to detect when it truly changes.
+     */
+    private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000;
+
     /* End of masks for mPrivateFlags3 */
 
     /**
@@ -3387,6 +3392,18 @@
      * decorations when they are shown.  You can perform layout of your inner
      * UI elements to account for non-fullscreen system UI through the
      * {@link #fitSystemWindows(Rect)} method.
+     *
+     * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed
+     *  differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the
+     *  window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode
+     *  layoutInDisplayCutoutMode} is
+     *  {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+     *  LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes.
+     *
+     * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode
+     * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+     * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+     * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
      */
     public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
 
@@ -4045,6 +4062,12 @@
     private CharSequence mContentDescription;
 
     /**
+     * If this view represents a distinct part of the window, it can have a title that labels the
+     * area.
+     */
+    private CharSequence mAccessibilityPaneTitle;
+
+    /**
      * Specifies the id of a view for which this view serves as a label for
      * accessibility purposes.
      */
@@ -4412,7 +4435,6 @@
     private CheckForLongPress mPendingCheckForLongPress;
     private CheckForTap mPendingCheckForTap = null;
     private PerformClick mPerformClick;
-    private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent;
 
     private UnsetPressedState mUnsetPressedState;
 
@@ -5409,6 +5431,11 @@
                         setScreenReaderFocusable(a.getBoolean(attr, false));
                     }
                     break;
+                case R.styleable.View_accessibilityPaneTitle:
+                    if (a.peekValue(attr) != null) {
+                        setAccessibilityPaneTitle(a.getString(attr));
+                    }
+                    break;
             }
         }
 
@@ -7164,7 +7191,7 @@
         if (gainFocus) {
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         } else {
-            notifyViewAccessibilityStateChangedIfNeeded(
+            notifyAccessibilityStateChanged(
                     AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
 
@@ -7218,6 +7245,34 @@
     }
 
     /**
+     * If this view is a visually distinct portion of a window, for example the content view of
+     * a fragment that is replaced, it is considered a pane for accessibility purposes. In order
+     * for accessibility services to understand the views role, and to announce its title as
+     * appropriate, such views should have pane titles.
+     *
+     * @param accessibilityPaneTitle The pane's title.
+     *
+     * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)}
+     */
+    public void setAccessibilityPaneTitle(CharSequence accessibilityPaneTitle) {
+        if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) {
+            mAccessibilityPaneTitle = accessibilityPaneTitle;
+            notifyAccessibilityStateChanged(AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE);
+        }
+    }
+
+    /**
+     * Get the title of the pane for purposes of accessibility.
+     *
+     * @return The current pane title.
+     *
+     * {@see #setAccessibilityPaneTitle}.
+     */
+    public CharSequence getAccessibilityPaneTitle() {
+        return mAccessibilityPaneTitle;
+    }
+
+    /**
      * Sends an accessibility event of the given type. If accessibility is
      * not enabled this method has no effect. The default implementation calls
      * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first
@@ -7316,7 +7371,12 @@
      * @hide
      */
     public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
-        if (!isShown()) {
+        // Panes disappearing are relevant even if though the view is no longer visible.
+        boolean isWindowStateChanged =
+                (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes()
+                & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0);
+        if (!isShown() && !isWindowDisappearedEvent) {
             return;
         }
         onInitializeAccessibilityEvent(event);
@@ -7424,6 +7484,10 @@
      * @hide
      */
     public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+        if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)
+                && !TextUtils.isEmpty(getAccessibilityPaneTitle())) {
+            event.getText().add(getAccessibilityPaneTitle());
+        }
     }
 
     /**
@@ -8514,6 +8578,7 @@
 
         info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN);
         populateAccessibilityNodeInfoDrawingOrderInParent(info);
+        info.setPaneTitle(mAccessibilityPaneTitle);
     }
 
     /**
@@ -8834,9 +8899,9 @@
         final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0;
         if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
             setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         } else {
-            notifyViewAccessibilityStateChangedIfNeeded(
+            notifyAccessibilityStateChanged(
                     AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION);
         }
     }
@@ -8869,7 +8934,7 @@
             return;
         }
         mAccessibilityTraversalBeforeId = beforeId;
-        notifyViewAccessibilityStateChangedIfNeeded(
+        notifyAccessibilityStateChanged(
                 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
     }
 
@@ -8913,7 +8978,7 @@
             return;
         }
         mAccessibilityTraversalAfterId = afterId;
-        notifyViewAccessibilityStateChangedIfNeeded(
+        notifyAccessibilityStateChanged(
                 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
     }
 
@@ -8956,7 +9021,7 @@
                 && mID == View.NO_ID) {
             mID = generateViewId();
         }
-        notifyViewAccessibilityStateChangedIfNeeded(
+        notifyAccessibilityStateChanged(
                 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
     }
 
@@ -10457,8 +10522,7 @@
 
         if (pflags3 != mPrivateFlags3) {
             mPrivateFlags3 = pflags3;
-            notifyViewAccessibilityStateChangedIfNeeded(
-                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+            notifyAccessibilityStateChanged(AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
     }
 
@@ -11286,7 +11350,7 @@
             mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
             mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT)
                     & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
-            notifyViewAccessibilityStateChangedIfNeeded(
+            notifyAccessibilityStateChanged(
                     AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
     }
@@ -11344,9 +11408,9 @@
             mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT)
                     & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
             if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) {
-                notifySubtreeAccessibilityStateChangedIfNeeded();
+                notifyAccessibilitySubtreeChanged();
             } else {
-                notifyViewAccessibilityStateChangedIfNeeded(
+                notifyAccessibilityStateChanged(
                         AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
             }
         }
@@ -11405,6 +11469,7 @@
      * {@link #getAccessibilityLiveRegion()} is not
      * {@link #ACCESSIBILITY_LIVE_REGION_NONE}.
      * </ul>
+     * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li>
      * </ol>
      *
      * @return Whether the view is exposed for accessibility.
@@ -11431,7 +11496,8 @@
 
         return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility()
                 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null
-                || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE;
+                || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE
+                || (mAccessibilityPaneTitle != null);
     }
 
     /**
@@ -11521,25 +11587,8 @@
      *
      * @hide
      */
-    public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) {
-        if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
-            return;
-        }
-        // If this is a live region, we should send a subtree change event
-        // from this view immediately. Otherwise, we can let it propagate up.
-        if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
-            final AccessibilityEvent event = AccessibilityEvent.obtain();
-            event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
-            event.setContentChangeTypes(changeType);
-            sendAccessibilityEventUnchecked(event);
-        } else if (mParent != null) {
-            try {
-                mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType);
-            } catch (AbstractMethodError e) {
-                Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
-                        " does not fully implement ViewParent", e);
-            }
-        }
+    public void notifyAccessibilityStateChanged(int changeType) {
+        notifyAccessibilityStateChanged(this, changeType);
     }
 
     /**
@@ -11553,22 +11602,42 @@
      *
      * @hide
      */
-    public void notifySubtreeAccessibilityStateChangedIfNeeded() {
+    public void notifyAccessibilitySubtreeChanged() {
+        if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) {
+            mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
+            notifyAccessibilityStateChanged(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+        }
+    }
+
+    void notifyAccessibilityStateChanged(View source, int changeType) {
         if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
             return;
         }
-        if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) {
-            mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
+        // Changes to views with a pane title count as window state changes, as the pane title
+        // marks them as significant parts of the UI.
+        if (!TextUtils.isEmpty(getAccessibilityPaneTitle())) {
+            final AccessibilityEvent event = AccessibilityEvent.obtain();
+            event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            event.setContentChangeTypes(changeType);
+            onPopulateAccessibilityEvent(event);
             if (mParent != null) {
                 try {
-                    mParent.notifySubtreeAccessibilityStateChanged(
-                            this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+                    mParent.requestSendAccessibilityEvent(this, event);
                 } catch (AbstractMethodError e) {
-                    Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
-                            " does not fully implement ViewParent", e);
+                    Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName()
+                            + " does not fully implement ViewParent", e);
                 }
             }
         }
+
+        if (mParent != null) {
+            try {
+                mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
+            } catch (AbstractMethodError e) {
+                Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName()
+                        + " does not fully implement ViewParent", e);
+            }
+        }
     }
 
     /**
@@ -11588,8 +11657,10 @@
     /**
      * Reset the flag indicating the accessibility state of the subtree rooted
      * at this view changed.
+     *
+     * @hide
      */
-    void resetSubtreeAccessibilityStateChanged() {
+    public void resetSubtreeAccessibilityStateChanged() {
         mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
     }
 
@@ -11750,7 +11821,7 @@
                         || getAccessibilitySelectionEnd() != end)
                         && (start == end)) {
                     setAccessibilitySelection(start, end);
-                    notifyViewAccessibilityStateChangedIfNeeded(
+                    notifyAccessibilityStateChanged(
                             AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
                     return true;
                 }
@@ -12492,6 +12563,10 @@
      */
     @CallSuper
     public void onVisibilityAggregated(boolean isVisible) {
+        // Update our internal visibility tracking so we can detect changes
+        boolean oldVisible = (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0;
+        mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE)
+                : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE);
         if (isVisible && mAttachInfo != null) {
             initialAwakenScrollBars();
         }
@@ -12532,6 +12607,13 @@
                 }
             }
         }
+        if (!TextUtils.isEmpty(getAccessibilityPaneTitle())) {
+            if (isVisible != oldVisible) {
+                notifyAccessibilityStateChanged(isVisible
+                        ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED
+                        : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED);
+            }
+        }
     }
 
     /**
@@ -13744,7 +13826,7 @@
                         ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) {
                     dispatchVisibilityAggregated(newVisibility == VISIBLE);
                 }
-                notifySubtreeAccessibilityStateChangedIfNeeded();
+                notifyAccessibilitySubtreeChanged();
             }
         }
 
@@ -13790,13 +13872,13 @@
                     || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0
                     || (changed & CONTEXT_CLICKABLE) != 0) {
                 if (oldIncludeForAccessibility != includeForAccessibility()) {
-                    notifySubtreeAccessibilityStateChangedIfNeeded();
+                    notifyAccessibilitySubtreeChanged();
                 } else {
-                    notifyViewAccessibilityStateChangedIfNeeded(
+                    notifyAccessibilityStateChanged(
                             AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
                 }
             } else if ((changed & ENABLED_MASK) != 0) {
-                notifyViewAccessibilityStateChangedIfNeeded(
+                notifyAccessibilityStateChanged(
                         AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
             }
         }
@@ -13831,10 +13913,13 @@
      * @param oldt Previous vertical scroll origin.
      */
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        notifyAccessibilitySubtreeChanged();
 
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt);
+        ViewRootImpl root = getViewRootImpl();
+        if (root != null) {
+            root.getAccessibilityState()
+                    .getSendViewScrolledAccessibilityEvent()
+                    .post(this, /* dx */ l - oldl, /* dy */ t - oldt);
         }
 
         mBackgroundSizeChanged = true;
@@ -14230,7 +14315,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -14274,7 +14359,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -14318,7 +14403,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -14355,7 +14440,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -14392,7 +14477,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -14595,7 +14680,7 @@
         if (mTransformationInfo.mAlpha != alpha) {
             // Report visibility changes, which can affect children, to accessibility
             if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) {
-                notifySubtreeAccessibilityStateChangedIfNeeded();
+                notifyAccessibilitySubtreeChanged();
             }
             mTransformationInfo.mAlpha = alpha;
             if (onSetAlpha((int) (alpha * 255))) {
@@ -15097,7 +15182,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -15131,7 +15216,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -15301,7 +15386,7 @@
     public void invalidateOutline() {
         rebuildOutline();
 
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        notifyAccessibilitySubtreeChanged();
         invalidateViewProperty(false, false);
     }
 
@@ -15496,7 +15581,7 @@
                 }
                 invalidateParentIfNeeded();
             }
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -15544,7 +15629,7 @@
                 }
                 invalidateParentIfNeeded();
             }
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
     }
 
@@ -16422,18 +16507,6 @@
     }
 
     /**
-     * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
-     * This event is sent at most once every
-     * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
-     */
-    private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) {
-        if (mSendViewScrolledAccessibilityEvent == null) {
-            mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent();
-        }
-        mSendViewScrolledAccessibilityEvent.post(dx, dy);
-    }
-
-    /**
      * Called by a parent to request that a child update its values for mScrollX
      * and mScrollY if necessary. This will typically be done if the child is
      * animating a scroll using a {@link android.widget.Scroller Scroller}
@@ -17688,7 +17761,13 @@
         removeUnsetPressCallback();
         removeLongPressCallback();
         removePerformClickCallback();
-        cancel(mSendViewScrolledAccessibilityEvent);
+        if (mAttachInfo != null
+                && mAttachInfo.mViewRootImpl.mAccessibilityState != null
+                && mAttachInfo.mViewRootImpl.mAccessibilityState.isScrollEventSenderInitialized()) {
+            mAttachInfo.mViewRootImpl.mAccessibilityState
+                    .getSendViewScrolledAccessibilityEvent()
+                    .cancelIfPendingFor(this);
+        }
         stopNestedScroll();
 
         // Anything that started animating right before detach should already
@@ -20307,7 +20386,7 @@
                 mForegroundInfo.mBoundsChanged = true;
             }
 
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
         return changed;
     }
@@ -21751,7 +21830,7 @@
             if (selected) {
                 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
             } else {
-                notifyViewAccessibilityStateChangedIfNeeded(
+                notifyAccessibilityStateChanged(
                         AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
             }
         }
@@ -26308,53 +26387,6 @@
     }
 
     /**
-     * Resuable callback for sending
-     * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event.
-     */
-    private class SendViewScrolledAccessibilityEvent implements Runnable {
-        public volatile boolean mIsPending;
-        public int mDeltaX;
-        public int mDeltaY;
-
-        public void post(int dx, int dy) {
-            mDeltaX += dx;
-            mDeltaY += dy;
-            if (!mIsPending) {
-                mIsPending = true;
-                postDelayed(this, ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
-            }
-        }
-
-        @Override
-        public void run() {
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                AccessibilityEvent event = AccessibilityEvent.obtain(
-                        AccessibilityEvent.TYPE_VIEW_SCROLLED);
-                event.setScrollDeltaX(mDeltaX);
-                event.setScrollDeltaY(mDeltaY);
-                sendAccessibilityEventUnchecked(event);
-            }
-            reset();
-        }
-
-        private void reset() {
-            mIsPending = false;
-            mDeltaX = 0;
-            mDeltaY = 0;
-        }
-    }
-
-    /**
-     * Remove the pending callback for sending a
-     * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event.
-     */
-    private void cancel(@Nullable SendViewScrolledAccessibilityEvent callback) {
-        if (callback == null || !callback.mIsPending) return;
-        removeCallbacks(callback);
-        callback.reset();
-    }
-
-    /**
      * <p>
      * This class represents a delegate that can be registered in a {@link View}
      * to enhance accessibility support via composition rather via inheritance.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 703364f..e0864bd 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3646,44 +3646,34 @@
         return ViewGroup.class.getName();
     }
 
-    @Override
-    public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
-        // If this is a live region, we should send a subtree change event
-        // from this view. Otherwise, we can let it propagate up.
-        if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
-            notifyViewAccessibilityStateChangedIfNeeded(
-                    AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
-        } else if (mParent != null) {
-            try {
-                mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
-            } catch (AbstractMethodError e) {
-                Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
-                        " does not fully implement ViewParent", e);
-            }
-        }
-    }
-
     /** @hide */
     @Override
-    public void notifySubtreeAccessibilityStateChangedIfNeeded() {
+    public void notifyAccessibilitySubtreeChanged() {
         if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
             return;
         }
         // If something important for a11y is happening in this subtree, make sure it's dispatched
         // from a view that is important for a11y so it doesn't get lost.
-        if ((getImportantForAccessibility() != IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
-                && !isImportantForAccessibility() && (getChildCount() > 0)) {
+        if (getImportantForAccessibility() != IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+                && !isImportantForAccessibility()
+                && getChildCount() > 0) {
             ViewParent a11yParent = getParentForAccessibility();
             if (a11yParent instanceof View) {
-                ((View) a11yParent).notifySubtreeAccessibilityStateChangedIfNeeded();
+                ((View) a11yParent).notifyAccessibilitySubtreeChanged();
                 return;
             }
         }
-        super.notifySubtreeAccessibilityStateChangedIfNeeded();
+        super.notifyAccessibilitySubtreeChanged();
     }
 
     @Override
-    void resetSubtreeAccessibilityStateChanged() {
+    public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
+        notifyAccessibilityStateChanged(source, changeType);
+    }
+
+    /** @hide */
+    @Override
+    public void resetSubtreeAccessibilityStateChanged() {
         super.resetSubtreeAccessibilityStateChanged();
         View[] children = mChildren;
         final int childCount = mChildrenCount;
@@ -5095,7 +5085,7 @@
         }
 
         if (child.getVisibility() != View.GONE) {
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
 
         if (mTransientIndices != null) {
@@ -5365,7 +5355,7 @@
         dispatchViewRemoved(view);
 
         if (view.getVisibility() != View.GONE) {
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            notifyAccessibilitySubtreeChanged();
         }
 
         int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
@@ -6084,7 +6074,7 @@
         if (invalidate) {
             invalidateViewProperty(false, false);
         }
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        notifyAccessibilitySubtreeChanged();
     }
 
     @Override
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6c5091c..fe3b696 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -20,7 +20,7 @@
 import static android.view.View.PFLAG_DRAW_ANIMATION;
 import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
-import static android.view.WindowManager.LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
@@ -89,9 +89,11 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeProvider;
+import android.view.accessibility.AccessibilityViewHierarchyState;
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
+import android.view.accessibility.ThrottlingAccessibilityEventSender;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.inputmethod.InputMethodManager;
@@ -113,7 +115,6 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.concurrent.CountDownLatch;
 
 /**
@@ -460,10 +461,6 @@
             new AccessibilityInteractionConnectionManager();
     final HighContrastTextManager mHighContrastTextManager;
 
-    SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
-
-    HashSet<View> mTempHashSet;
-
     private final int mDensity;
     private final int mNoncompatDensity;
 
@@ -478,6 +475,8 @@
 
     private boolean mNeedsRendererSetup;
 
+    protected AccessibilityViewHierarchyState mAccessibilityState;
+
     /**
      * Consistency verifier for debugging purposes.
      */
@@ -1597,9 +1596,9 @@
 
     void dispatchApplyInsets(View host) {
         WindowInsets insets = getWindowInsets(true /* forceConstruct */);
-        final boolean layoutInCutout =
-                (mWindowAttributes.flags2 & FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA) != 0;
-        if (!layoutInCutout) {
+        final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
+                == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
+        if (!dispatchCutout) {
             // Window is either not laid out in cutout or the status bar inset takes care of
             // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
             insets = insets.consumeDisplayCutout();
@@ -7262,11 +7261,9 @@
      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
      */
     private void postSendWindowContentChangedCallback(View source, int changeType) {
-        if (mSendWindowContentChangedAccessibilityEvent == null) {
-            mSendWindowContentChangedAccessibilityEvent =
-                new SendWindowContentChangedAccessibilityEvent();
-        }
-        mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
+        getAccessibilityState()
+                .getSendWindowContentChangedAccessibilityEvent()
+                .runOrPost(source, changeType);
     }
 
     /**
@@ -7274,11 +7271,20 @@
      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
      */
     private void removeSendWindowContentChangedCallback() {
-        if (mSendWindowContentChangedAccessibilityEvent != null) {
-            mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
+        if (mAccessibilityState != null
+                && mAccessibilityState.isWindowContentChangedEventSenderInitialized()) {
+            ThrottlingAccessibilityEventSender.cancelIfPending(
+                    mAccessibilityState.getSendWindowContentChangedAccessibilityEvent());
         }
     }
 
+    AccessibilityViewHierarchyState getAccessibilityState() {
+        if (mAccessibilityState == null) {
+            mAccessibilityState = new AccessibilityViewHierarchyState();
+        }
+        return mAccessibilityState;
+    }
+
     @Override
     public boolean showContextMenuForChild(View originalView) {
         return false;
@@ -7314,12 +7320,8 @@
             return false;
         }
 
-        // Immediately flush pending content changed event (if any) to preserve event order
-        if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
-                && mSendWindowContentChangedAccessibilityEvent != null
-                && mSendWindowContentChangedAccessibilityEvent.mSource != null) {
-            mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun();
-        }
+        // Send any pending event to prevent reordering
+        flushPendingAccessibilityEvents();
 
         // Intercept accessibility focus events fired by virtual nodes to keep
         // track of accessibility focus position in such nodes.
@@ -7363,6 +7365,19 @@
         return true;
     }
 
+    /** @hide */
+    public void flushPendingAccessibilityEvents() {
+        if (mAccessibilityState != null) {
+            if (mAccessibilityState.isScrollEventSenderInitialized()) {
+                mAccessibilityState.getSendViewScrolledAccessibilityEvent().sendNowIfPending();
+            }
+            if (mAccessibilityState.isWindowContentChangedEventSenderInitialized()) {
+                mAccessibilityState.getSendWindowContentChangedAccessibilityEvent()
+                        .sendNowIfPending();
+            }
+        }
+    }
+
     /**
      * Updates the focused virtual view, when necessary, in response to a
      * content changed event.
@@ -7497,39 +7512,6 @@
         return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
     }
 
-    private View getCommonPredecessor(View first, View second) {
-        if (mTempHashSet == null) {
-            mTempHashSet = new HashSet<View>();
-        }
-        HashSet<View> seen = mTempHashSet;
-        seen.clear();
-        View firstCurrent = first;
-        while (firstCurrent != null) {
-            seen.add(firstCurrent);
-            ViewParent firstCurrentParent = firstCurrent.mParent;
-            if (firstCurrentParent instanceof View) {
-                firstCurrent = (View) firstCurrentParent;
-            } else {
-                firstCurrent = null;
-            }
-        }
-        View secondCurrent = second;
-        while (secondCurrent != null) {
-            if (seen.contains(secondCurrent)) {
-                seen.clear();
-                return secondCurrent;
-            }
-            ViewParent secondCurrentParent = secondCurrent.mParent;
-            if (secondCurrentParent instanceof View) {
-                secondCurrent = (View) secondCurrentParent;
-            } else {
-                secondCurrent = null;
-            }
-        }
-        seen.clear();
-        return null;
-    }
-
     void checkThread() {
         if (mThread != Thread.currentThread()) {
             throw new CalledFromWrongThreadException(
@@ -8140,80 +8122,6 @@
         }
     }
 
-    private class SendWindowContentChangedAccessibilityEvent implements Runnable {
-        private int mChangeTypes = 0;
-
-        public View mSource;
-        public long mLastEventTimeMillis;
-
-        @Override
-        public void run() {
-            // Protect against re-entrant code and attempt to do the right thing in the case that
-            // we're multithreaded.
-            View source = mSource;
-            mSource = null;
-            if (source == null) {
-                Log.e(TAG, "Accessibility content change has no source");
-                return;
-            }
-            // The accessibility may be turned off while we were waiting so check again.
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                mLastEventTimeMillis = SystemClock.uptimeMillis();
-                AccessibilityEvent event = AccessibilityEvent.obtain();
-                event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
-                event.setContentChangeTypes(mChangeTypes);
-                source.sendAccessibilityEventUnchecked(event);
-            } else {
-                mLastEventTimeMillis = 0;
-            }
-            // In any case reset to initial state.
-            source.resetSubtreeAccessibilityStateChanged();
-            mChangeTypes = 0;
-        }
-
-        public void runOrPost(View source, int changeType) {
-            if (mHandler.getLooper() != Looper.myLooper()) {
-                CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the "
-                        + "original thread that created a view hierarchy can touch its views.");
-                // TODO: Throw the exception
-                Log.e(TAG, "Accessibility content change on non-UI thread. Future Android "
-                        + "versions will throw an exception.", e);
-                // Attempt to recover. This code does not eliminate the thread safety issue, but
-                // it should force any issues to happen near the above log.
-                mHandler.removeCallbacks(this);
-                if (mSource != null) {
-                    // Dispatch whatever was pending. It's still possible that the runnable started
-                    // just before we removed the callbacks, and bad things will happen, but at
-                    // least they should happen very close to the logged error.
-                    run();
-                }
-            }
-            if (mSource != null) {
-                // If there is no common predecessor, then mSource points to
-                // a removed view, hence in this case always prefer the source.
-                View predecessor = getCommonPredecessor(mSource, source);
-                mSource = (predecessor != null) ? predecessor : source;
-                mChangeTypes |= changeType;
-                return;
-            }
-            mSource = source;
-            mChangeTypes = changeType;
-            final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
-            final long minEventIntevalMillis =
-                    ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
-            if (timeSinceLastMillis >= minEventIntevalMillis) {
-                removeCallbacksAndRun();
-            } else {
-                mHandler.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
-            }
-        }
-
-        public void removeCallbacksAndRun() {
-            mHandler.removeCallbacks(this);
-            run();
-        }
-    }
-
     private static class KeyFallbackManager {
 
         // This is used to ensure that key-fallback events are only dispatched once. We attempt
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a65aba1..ae3c4f09 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -889,7 +889,12 @@
          *  decorations around the border (such as the status bar).  The
          *  window must correctly position its contents to take the screen
          *  decoration into account.  This flag is normally set for you
-         *  by Window as described in {@link Window#setFlags}. */
+         *  by Window as described in {@link Window#setFlags}.
+         *
+         *  <p>Note: on displays that have a {@link DisplayCutout}, the window may be placed
+         *  such that it avoids the {@link DisplayCutout} area if necessary according to the
+         *  {@link #layoutInDisplayCutoutMode}.
+         */
         public static final int FLAG_LAYOUT_IN_SCREEN   = 0x00000100;
 
         /** Window flag: allow window to extend outside of the screen. */
@@ -1299,26 +1304,11 @@
         @Retention(RetentionPolicy.SOURCE)
         @LongDef(
             flag = true,
-            value = {
-                    LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA,
-            })
+            value = {})
         @interface Flags2 {}
 
         /**
-         * Window flag: allow placing the window within the area that overlaps with the
-         * display cutout.
-         *
-         * <p>
-         * The window must correctly position its contents to take the display cutout into account.
-         *
-         * @see DisplayCutout
-         */
-        public static final long FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA = 0x00000001;
-
-        /**
          * Various behavioral options/flags.  Default is none.
-         *
-         * @see #FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA
          */
         @Flags2 public long flags2;
 
@@ -2050,6 +2040,77 @@
          */
         public boolean hasSystemUiListeners;
 
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(
+                flag = true,
+                value = {LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,
+                        LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS,
+                        LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER})
+        @interface LayoutInDisplayCutoutMode {}
+
+        /**
+         * Controls how the window is laid out if there is a {@link DisplayCutout}.
+         *
+         * <p>
+         * Defaults to {@link #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}.
+         *
+         * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+         * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+         * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
+         * @see DisplayCutout
+         */
+        @LayoutInDisplayCutoutMode
+        public int layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+
+        /**
+         * The window is allowed to extend into the {@link DisplayCutout} area, only if the
+         * {@link DisplayCutout} is fully contained within the status bar. Otherwise, the window is
+         * laid out such that it does not overlap with the {@link DisplayCutout} area.
+         *
+         * <p>
+         * In practice, this means that if the window did not set FLAG_FULLSCREEN or
+         * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait.
+         * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does overlap the
+         * cutout area.
+         *
+         * <p>
+         * The usual precautions for not overlapping with the status bar are sufficient for ensuring
+         * that no important content overlaps with the DisplayCutout.
+         *
+         * @see DisplayCutout
+         * @see WindowInsets
+         */
+        public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;
+
+        /**
+         * The window is always allowed to extend into the {@link DisplayCutout} area,
+         * even if fullscreen or in landscape.
+         *
+         * <p>
+         * The window must make sure that no important content overlaps with the
+         * {@link DisplayCutout}.
+         *
+         * @see DisplayCutout
+         * @see WindowInsets#getDisplayCutout()
+         */
+        public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;
+
+        /**
+         * The window is never allowed to overlap with the DisplayCutout area.
+         *
+         * <p>
+         * This should be used with windows that transiently set SYSTEM_UI_FLAG_FULLSCREEN to
+         * avoid a relayout of the window when the flag is set or cleared.
+         *
+         * @see DisplayCutout
+         * @see View#SYSTEM_UI_FLAG_FULLSCREEN SYSTEM_UI_FLAG_FULLSCREEN
+         * @see View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+         */
+        public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;
+
+
         /**
          * When this window has focus, disable touch pad pointer gesture processing.
          * The window will receive raw position updates from the touch pad instead
@@ -2276,6 +2337,7 @@
             out.writeLong(flags2);
             out.writeInt(privateFlags);
             out.writeInt(softInputMode);
+            out.writeInt(layoutInDisplayCutoutMode);
             out.writeInt(gravity);
             out.writeFloat(horizontalMargin);
             out.writeFloat(verticalMargin);
@@ -2332,6 +2394,7 @@
             flags2 = in.readLong();
             privateFlags = in.readInt();
             softInputMode = in.readInt();
+            layoutInDisplayCutoutMode = in.readInt();
             gravity = in.readInt();
             horizontalMargin = in.readFloat();
             verticalMargin = in.readFloat();
@@ -2474,6 +2537,10 @@
                 softInputMode = o.softInputMode;
                 changes |= SOFT_INPUT_MODE_CHANGED;
             }
+            if (layoutInDisplayCutoutMode != o.layoutInDisplayCutoutMode) {
+                layoutInDisplayCutoutMode = o.layoutInDisplayCutoutMode;
+                changes |= LAYOUT_CHANGED;
+            }
             if (gravity != o.gravity) {
                 gravity = o.gravity;
                 changes |= LAYOUT_CHANGED;
@@ -2651,6 +2718,10 @@
                 sb.append(softInputModeToString(softInputMode));
                 sb.append('}');
             }
+            if (layoutInDisplayCutoutMode != 0) {
+                sb.append(" layoutInDisplayCutoutMode=");
+                sb.append(layoutInDisplayCutoutModeToString(layoutInDisplayCutoutMode));
+            }
             sb.append(" ty=");
             sb.append(ViewDebug.intToString(LayoutParams.class, "type", type));
             if (format != PixelFormat.OPAQUE) {
@@ -2849,6 +2920,20 @@
                     && height == WindowManager.LayoutParams.MATCH_PARENT;
         }
 
+        private static String layoutInDisplayCutoutModeToString(
+                @LayoutInDisplayCutoutMode int mode) {
+            switch (mode) {
+                case LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT:
+                    return "default";
+                case LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS:
+                    return "always";
+                case LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER:
+                    return "never";
+                default:
+                    return "unknown(" + mode + ")";
+            }
+        }
+
         private static String softInputModeToString(@SoftInputModeFlags int softInputMode) {
             final StringBuilder result = new StringBuilder();
             final int state = softInputMode & SOFT_INPUT_MASK_STATE;
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 9c1c9e3..a6f36bb 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -45,6 +45,11 @@
     int PRESENCE_INTERNAL = 1 << 0;
     int PRESENCE_EXTERNAL = 1 << 1;
 
+    // Navigation bar position values
+    int NAV_BAR_LEFT = 1 << 0;
+    int NAV_BAR_RIGHT = 1 << 1;
+    int NAV_BAR_BOTTOM = 1 << 2;
+
     /**
      * Sticky broadcast of the current HDMI plugged state.
      */
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 6c2d349..e0f74a7 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -192,9 +192,11 @@
  * <b>TRANSITION TYPES</b></br>
  * </p>
  * <p>
- * <b>Window state changed</b> - represents the event of opening a
- * {@link android.widget.PopupWindow}, {@link android.view.Menu},
- * {@link android.app.Dialog}, etc.</br>
+ * <b>Window state changed</b> - represents the event of a change to a section of
+ * the user interface that is visually distinct. Should be sent from either the
+ * root view of a window or from a view that is marked as a pane
+ * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Not that changes
+ * to true windows are represented by {@link #TYPE_WINDOWS_CHANGED}.</br>
  * <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br>
  * <em>Properties:</em></br>
  * <ul>
@@ -203,7 +205,7 @@
  *   <li>{@link #getClassName()} - The class name of the source.</li>
  *   <li>{@link #getPackageName()} - The package name of the source.</li>
  *   <li>{@link #getEventTime()}  - The event time.</li>
- *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
+ *   <li>{@link #getText()} - The text of the source's sub-tree, including the pane titles.</li>
  * </ul>
  * </p>
  * <p>
@@ -436,8 +438,10 @@
     public static final int TYPE_VIEW_TEXT_CHANGED = 0x00000010;
 
     /**
-     * Represents the event of opening a {@link android.widget.PopupWindow},
-     * {@link android.view.Menu}, {@link android.app.Dialog}, etc.
+     * Represents the event of a change to a visually distinct section of the user interface.
+     * These events should only be dispatched from {@link android.view.View}s that have
+     * accessibility pane titles, and replaces {@link #TYPE_WINDOW_CONTENT_CHANGED} for those
+     * sources. Details about the change are available from {@link #getContentChangeTypes()}.
      */
     public static final int TYPE_WINDOW_STATE_CHANGED = 0x00000020;
 
@@ -565,6 +569,30 @@
     public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000004;
 
     /**
+     * Change type for {@link #TYPE_WINDOW_STATE_CHANGED} event:
+     * The node's pane title changed.
+     */
+    public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 0x00000008;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_STATE_CHANGED} event:
+     * The node has a pane title, and either just appeared or just was assigned a title when it
+     * had none before.
+     */
+    public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 0x00000010;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_STATE_CHANGED} event:
+     * Can mean one of two slightly different things. The primary meaning is that the node has
+     * a pane title, and was removed from the node hierarchy. It will also be sent if the pane
+     * title is set to {@code null} after it contained a title.
+     * No source will be returned if the node is no longer on the screen. To make the change more
+     * clear for the user, the first entry in {@link #getText()} will return the value that would
+     * have been returned by {@code getSource().getPaneTitle()}.
+     */
+    public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 0x00000020;
+
+    /**
      * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
      * The window was added.
      */
@@ -654,7 +682,8 @@
                     CONTENT_CHANGE_TYPE_UNDEFINED,
                     CONTENT_CHANGE_TYPE_SUBTREE,
                     CONTENT_CHANGE_TYPE_TEXT,
-                    CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION
+                    CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION,
+                    CONTENT_CHANGE_TYPE_PANE_TITLE
             })
     public @interface ContentChangeTypes {}
 
@@ -1244,43 +1273,33 @@
         builder.append("EventType: ").append(eventTypeToString(mEventType));
         builder.append("; EventTime: ").append(mEventTime);
         builder.append("; PackageName: ").append(mPackageName);
-        builder.append("; MovementGranularity: ").append(mMovementGranularity);
-        builder.append("; Action: ").append(mAction);
-        builder.append("; ContentChangeTypes: ").append(
-                contentChangeTypesToString(mContentChangeTypes));
-        builder.append("; WindowChangeTypes: ").append(
-                windowChangeTypesToString(mWindowChangeTypes));
-        builder.append(super.toString());
-        if (DEBUG) {
-            builder.append("\n");
-            builder.append("; sourceWindowId: ").append(mSourceWindowId);
-            builder.append("; mSourceNodeId: ").append(mSourceNodeId);
-            for (int i = 0; i < getRecordCount(); i++) {
-                final AccessibilityRecord record = getRecord(i);
-                builder.append("  Record ");
-                builder.append(i);
-                builder.append(":");
-                builder.append(" [ ClassName: " + record.mClassName);
-                builder.append("; Text: " + record.mText);
-                builder.append("; ContentDescription: " + record.mContentDescription);
-                builder.append("; ItemCount: " + record.mItemCount);
-                builder.append("; CurrentItemIndex: " + record.mCurrentItemIndex);
-                builder.append("; IsEnabled: " + record.isEnabled());
-                builder.append("; IsPassword: " + record.isPassword());
-                builder.append("; IsChecked: " + record.isChecked());
-                builder.append("; IsFullScreen: " + record.isFullScreen());
-                builder.append("; Scrollable: " + record.isScrollable());
-                builder.append("; BeforeText: " + record.mBeforeText);
-                builder.append("; FromIndex: " + record.mFromIndex);
-                builder.append("; ToIndex: " + record.mToIndex);
-                builder.append("; ScrollX: " + record.mScrollX);
-                builder.append("; ScrollY: " + record.mScrollY);
-                builder.append("; AddedCount: " + record.mAddedCount);
-                builder.append("; RemovedCount: " + record.mRemovedCount);
-                builder.append("; ParcelableData: " + record.mParcelableData);
-                builder.append(" ]");
+        if (!DEBUG_CONCISE_TOSTRING || mMovementGranularity != 0) {
+            builder.append("; MovementGranularity: ").append(mMovementGranularity);
+        }
+        if (!DEBUG_CONCISE_TOSTRING || mAction != 0) {
+            builder.append("; Action: ").append(mAction);
+        }
+        if (!DEBUG_CONCISE_TOSTRING || mContentChangeTypes != 0) {
+            builder.append("; ContentChangeTypes: ").append(
+                    contentChangeTypesToString(mContentChangeTypes));
+        }
+        if (!DEBUG_CONCISE_TOSTRING || mWindowChangeTypes != 0) {
+            builder.append("; WindowChangeTypes: ").append(
+                    contentChangeTypesToString(mWindowChangeTypes));
+        }
+        super.appendTo(builder);
+        if (DEBUG || DEBUG_CONCISE_TOSTRING) {
+            if (!DEBUG_CONCISE_TOSTRING) {
                 builder.append("\n");
             }
+            if (DEBUG) {
+                builder.append("; SourceWindowId: ").append(mSourceWindowId);
+                builder.append("; SourceNodeId: ").append(mSourceNodeId);
+            }
+            for (int i = 0; i < getRecordCount(); i++) {
+                builder.append("  Record ").append(i).append(":");
+                getRecord(i).appendTo(builder).append("\n");
+            }
         } else {
             builder.append("; recordCount: ").append(getRecordCount());
         }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 28ef697..311dd4b 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -723,6 +723,7 @@
     private CharSequence mText;
     private CharSequence mHintText;
     private CharSequence mError;
+    private CharSequence mPaneTitle;
     private CharSequence mContentDescription;
     private String mViewIdResourceName;
     private ArrayList<String> mExtraDataKeys;
@@ -2033,6 +2034,33 @@
     }
 
     /**
+     * If this node represents a visually distinct region of the screen that may update separately
+     * from the rest of the window, it is considered a pane. Set the pane title to indicate that
+     * the node is a pane, and to provide a title for it.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     * @param paneTitle The title of the pane represented by this node.
+     */
+    public void setPaneTitle(@Nullable CharSequence paneTitle) {
+        enforceNotSealed();
+        mPaneTitle = (paneTitle == null)
+                ? null : paneTitle.subSequence(0, paneTitle.length());
+    }
+
+    /**
+     * Get the title of the pane represented by this node.
+     *
+     * @return The title of the pane represented by this node, or {@code null} if this node does
+     *         not represent a pane.
+     */
+    public @Nullable CharSequence getPaneTitle() {
+        return mPaneTitle;
+    }
+
+    /**
      * Get the drawing order of the view corresponding it this node.
      * <p>
      * Drawing order is determined only within the node's parent, so this index is only relative
@@ -3151,6 +3179,10 @@
             nonDefaultFields |= bitAt(fieldIndex);
         }
         fieldIndex++;
+        if (!Objects.equals(mPaneTitle, DEFAULT.mPaneTitle)) {
+            nonDefaultFields |= bitAt(fieldIndex);
+        }
+        fieldIndex++;
         if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) {
             nonDefaultFields |= bitAt(fieldIndex);
         }
@@ -3270,6 +3302,7 @@
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
             parcel.writeCharSequence(mContentDescription);
         }
+        if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPaneTitle);
         if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName);
 
         if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart);
@@ -3341,6 +3374,7 @@
         mHintText = other.mHintText;
         mError = other.mError;
         mContentDescription = other.mContentDescription;
+        mPaneTitle = other.mPaneTitle;
         mViewIdResourceName = other.mViewIdResourceName;
 
         if (mActions != null) mActions.clear();
@@ -3461,6 +3495,7 @@
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
             mContentDescription = parcel.readCharSequence();
         }
+        if (isBitSet(nonDefaultFields, fieldIndex++)) mPaneTitle = parcel.readString();
         if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString();
 
         if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt();
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index fa505c9..0a709f8 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -16,6 +16,8 @@
 
 package android.view.accessibility;
 
+import static com.android.internal.util.CollectionUtils.isEmpty;
+
 import android.annotation.Nullable;
 import android.os.Parcelable;
 import android.view.View;
@@ -55,6 +57,8 @@
  * @see AccessibilityNodeInfo
  */
 public class AccessibilityRecord {
+    /** @hide */
+    protected static final boolean DEBUG_CONCISE_TOSTRING = false;
 
     private static final int UNDEFINED = -1;
 
@@ -888,28 +892,69 @@
 
     @Override
     public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append(" [ ClassName: " + mClassName);
-        builder.append("; Text: " + mText);
-        builder.append("; ContentDescription: " + mContentDescription);
-        builder.append("; ItemCount: " + mItemCount);
-        builder.append("; CurrentItemIndex: " + mCurrentItemIndex);
-        builder.append("; IsEnabled: " + getBooleanProperty(PROPERTY_ENABLED));
-        builder.append("; IsPassword: " + getBooleanProperty(PROPERTY_PASSWORD));
-        builder.append("; IsChecked: " + getBooleanProperty(PROPERTY_CHECKED));
-        builder.append("; IsFullScreen: " + getBooleanProperty(PROPERTY_FULL_SCREEN));
-        builder.append("; Scrollable: " + getBooleanProperty(PROPERTY_SCROLLABLE));
-        builder.append("; BeforeText: " + mBeforeText);
-        builder.append("; FromIndex: " + mFromIndex);
-        builder.append("; ToIndex: " + mToIndex);
-        builder.append("; ScrollX: " + mScrollX);
-        builder.append("; ScrollY: " + mScrollY);
-        builder.append("; MaxScrollX: " + mMaxScrollX);
-        builder.append("; MaxScrollY: " + mMaxScrollY);
-        builder.append("; AddedCount: " + mAddedCount);
-        builder.append("; RemovedCount: " + mRemovedCount);
-        builder.append("; ParcelableData: " + mParcelableData);
+        return appendTo(new StringBuilder()).toString();
+    }
+
+    StringBuilder appendTo(StringBuilder builder) {
+        builder.append(" [ ClassName: ").append(mClassName);
+        if (!DEBUG_CONCISE_TOSTRING || !isEmpty(mText)) {
+            appendPropName(builder, "Text").append(mText);
+        }
+        append(builder, "ContentDescription", mContentDescription);
+        append(builder, "ItemCount", mItemCount);
+        append(builder, "CurrentItemIndex", mCurrentItemIndex);
+
+        appendUnless(true, PROPERTY_ENABLED, builder);
+        appendUnless(false, PROPERTY_PASSWORD, builder);
+        appendUnless(false, PROPERTY_CHECKED, builder);
+        appendUnless(false, PROPERTY_FULL_SCREEN, builder);
+        appendUnless(false, PROPERTY_SCROLLABLE, builder);
+
+        append(builder, "BeforeText", mBeforeText);
+        append(builder, "FromIndex", mFromIndex);
+        append(builder, "ToIndex", mToIndex);
+        append(builder, "ScrollX", mScrollX);
+        append(builder, "ScrollY", mScrollY);
+        append(builder, "MaxScrollX", mMaxScrollX);
+        append(builder, "MaxScrollY", mMaxScrollY);
+        append(builder, "AddedCount", mAddedCount);
+        append(builder, "RemovedCount", mRemovedCount);
+        append(builder, "ParcelableData", mParcelableData);
         builder.append(" ]");
-        return builder.toString();
+        return builder;
+    }
+
+    private void appendUnless(boolean defValue, int prop, StringBuilder builder) {
+        boolean value = getBooleanProperty(prop);
+        if (DEBUG_CONCISE_TOSTRING && value == defValue) return;
+        appendPropName(builder, singleBooleanPropertyToString(prop))
+                .append(value);
+    }
+
+    private static String singleBooleanPropertyToString(int prop) {
+        switch (prop) {
+            case PROPERTY_CHECKED: return "Checked";
+            case PROPERTY_ENABLED: return "Enabled";
+            case PROPERTY_PASSWORD: return "Password";
+            case PROPERTY_FULL_SCREEN: return "FullScreen";
+            case PROPERTY_SCROLLABLE: return "Scrollable";
+            case PROPERTY_IMPORTANT_FOR_ACCESSIBILITY:
+                return "ImportantForAccessibility";
+            default: return Integer.toHexString(prop);
+        }
+    }
+
+    private void append(StringBuilder builder, String propName, int propValue) {
+        if (DEBUG_CONCISE_TOSTRING && propValue == UNDEFINED) return;
+        appendPropName(builder, propName).append(propValue);
+    }
+
+    private void append(StringBuilder builder, String propName, Object propValue) {
+        if (DEBUG_CONCISE_TOSTRING && propValue == null) return;
+        appendPropName(builder, propName).append(propValue);
+    }
+
+    private StringBuilder appendPropName(StringBuilder builder, String propName) {
+        return builder.append("; ").append(propName).append(": ");
     }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityViewHierarchyState.java b/core/java/android/view/accessibility/AccessibilityViewHierarchyState.java
new file mode 100644
index 0000000..447fafa
--- /dev/null
+++ b/core/java/android/view/accessibility/AccessibilityViewHierarchyState.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Accessibility-related state of a {@link android.view.ViewRootImpl}
+ *
+ * @hide
+ */
+public class AccessibilityViewHierarchyState {
+    private @Nullable SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent;
+    private @Nullable SendWindowContentChangedAccessibilityEvent
+            mSendWindowContentChangedAccessibilityEvent;
+
+    /**
+     * @return a {@link SendViewScrolledAccessibilityEvent}, creating one if needed
+     */
+    public @NonNull SendViewScrolledAccessibilityEvent getSendViewScrolledAccessibilityEvent() {
+        if (mSendViewScrolledAccessibilityEvent == null) {
+            mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent();
+        }
+        return mSendViewScrolledAccessibilityEvent;
+    }
+
+    public boolean isScrollEventSenderInitialized() {
+        return mSendViewScrolledAccessibilityEvent != null;
+    }
+
+    /**
+     * @return a {@link SendWindowContentChangedAccessibilityEvent}, creating one if needed
+     */
+    public @NonNull SendWindowContentChangedAccessibilityEvent
+            getSendWindowContentChangedAccessibilityEvent() {
+        if (mSendWindowContentChangedAccessibilityEvent == null) {
+            mSendWindowContentChangedAccessibilityEvent =
+                    new SendWindowContentChangedAccessibilityEvent();
+        }
+        return mSendWindowContentChangedAccessibilityEvent;
+    }
+
+    public boolean isWindowContentChangedEventSenderInitialized() {
+        return mSendWindowContentChangedAccessibilityEvent != null;
+    }
+}
diff --git a/core/java/android/view/accessibility/SendViewScrolledAccessibilityEvent.java b/core/java/android/view/accessibility/SendViewScrolledAccessibilityEvent.java
new file mode 100644
index 0000000..40a1b6a
--- /dev/null
+++ b/core/java/android/view/accessibility/SendViewScrolledAccessibilityEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility;
+
+
+import android.annotation.NonNull;
+import android.view.View;
+
+/**
+ * Sender for {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event.
+ *
+ * @hide
+ */
+public class SendViewScrolledAccessibilityEvent extends ThrottlingAccessibilityEventSender {
+
+    public int mDeltaX;
+    public int mDeltaY;
+
+    /**
+     * Post a scroll event to be sent for the given view
+     */
+    public void post(View source, int dx, int dy) {
+        if (!isPendingFor(source)) sendNowIfPending();
+
+        mDeltaX += dx;
+        mDeltaY += dy;
+
+        if (!isPendingFor(source)) scheduleFor(source);
+    }
+
+    @Override
+    protected void performSendEvent(@NonNull View source) {
+        AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
+        event.setScrollDeltaX(mDeltaX);
+        event.setScrollDeltaY(mDeltaY);
+        source.sendAccessibilityEventUnchecked(event);
+    }
+
+    @Override
+    protected void resetState(@NonNull View source) {
+        mDeltaX = 0;
+        mDeltaY = 0;
+    }
+}
diff --git a/core/java/android/view/accessibility/SendWindowContentChangedAccessibilityEvent.java b/core/java/android/view/accessibility/SendWindowContentChangedAccessibilityEvent.java
new file mode 100644
index 0000000..df38fba
--- /dev/null
+++ b/core/java/android/view/accessibility/SendWindowContentChangedAccessibilityEvent.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility;
+
+
+import static com.android.internal.util.ObjectUtils.firstNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.view.View;
+import android.view.ViewParent;
+
+import java.util.HashSet;
+
+/**
+ * @hide
+ */
+public class SendWindowContentChangedAccessibilityEvent
+        extends ThrottlingAccessibilityEventSender {
+
+    private int mChangeTypes = 0;
+
+    private HashSet<View> mTempHashSet;
+
+    @Override
+    protected void performSendEvent(@NonNull View source) {
+        AccessibilityEvent event = AccessibilityEvent.obtain();
+        event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        event.setContentChangeTypes(mChangeTypes);
+        source.sendAccessibilityEventUnchecked(event);
+    }
+
+    @Override
+    protected void resetState(@Nullable View source) {
+        if (source != null) {
+            source.resetSubtreeAccessibilityStateChanged();
+        }
+        mChangeTypes = 0;
+    }
+
+    /**
+     * Post the {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event with the given
+     * {@link AccessibilityEvent#getContentChangeTypes change type} for the given view
+     */
+    public void runOrPost(View source, int changeType) {
+        if (source.getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) {
+            sendNowIfPending();
+            mChangeTypes = changeType;
+            sendNow(source);
+        } else {
+            mChangeTypes |= changeType;
+            scheduleFor(source);
+        }
+    }
+
+    @Override
+    protected @Nullable View tryMerge(@NonNull View oldSource, @NonNull View newSource) {
+        // If there is no common predecessor, then oldSource points to
+        // a removed view, hence in this case always prefer the newSource.
+        return firstNotNull(
+                getCommonPredecessor(oldSource, newSource),
+                newSource);
+    }
+
+    private View getCommonPredecessor(View first, View second) {
+        if (mTempHashSet == null) {
+            mTempHashSet = new HashSet<>();
+        }
+        HashSet<View> seen = mTempHashSet;
+        seen.clear();
+        View firstCurrent = first;
+        while (firstCurrent != null) {
+            seen.add(firstCurrent);
+            ViewParent firstCurrentParent = firstCurrent.getParent();
+            if (firstCurrentParent instanceof View) {
+                firstCurrent = (View) firstCurrentParent;
+            } else {
+                firstCurrent = null;
+            }
+        }
+        View secondCurrent = second;
+        while (secondCurrent != null) {
+            if (seen.contains(secondCurrent)) {
+                seen.clear();
+                return secondCurrent;
+            }
+            ViewParent secondCurrentParent = secondCurrent.getParent();
+            if (secondCurrentParent instanceof View) {
+                secondCurrent = (View) secondCurrentParent;
+            } else {
+                secondCurrent = null;
+            }
+        }
+        seen.clear();
+        return null;
+    }
+}
diff --git a/core/java/android/view/accessibility/ThrottlingAccessibilityEventSender.java b/core/java/android/view/accessibility/ThrottlingAccessibilityEventSender.java
new file mode 100644
index 0000000..66fa301
--- /dev/null
+++ b/core/java/android/view/accessibility/ThrottlingAccessibilityEventSender.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility;
+
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewRootImpl;
+import android.view.ViewRootImpl.CalledFromWrongThreadException;
+
+/**
+ * A throttling {@link AccessibilityEvent} sender that relies on its currently associated
+ * 'source' view's {@link View#postDelayed delayed execution} to delay and possibly
+ * {@link #tryMerge merge} together any events that come in less than
+ * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval
+ * the configured amount of milliseconds} apart.
+ *
+ * The suggested usage is to create a singleton extending this class, holding any state specific to
+ * the particular event type that the subclass represents, and have an 'entrypoint' method that
+ * delegates to {@link #scheduleFor(View)}.
+ * For example:
+ *
+ * {@code
+ *     public void post(View view, String text, int resId) {
+ *         mText = text;
+ *         mId = resId;
+ *         scheduleFor(view);
+ *     }
+ * }
+ *
+ * @see #scheduleFor(View)
+ * @see #tryMerge(View, View)
+ * @see #performSendEvent(View)
+ * @hide
+ */
+public abstract class ThrottlingAccessibilityEventSender {
+
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "ThrottlingA11ySender";
+
+    View mSource;
+    private long mLastSendTimeMillis = Long.MIN_VALUE;
+    private boolean mIsPending = false;
+
+    private final Runnable mWorker = () -> {
+        View source = mSource;
+        if (DEBUG) Log.d(LOG_TAG, thisClass() + ".run(mSource = " + source + ")");
+
+        if (!checkAndResetIsPending() || source == null) {
+            resetStateInternal();
+            return;
+        }
+
+        // Accessibility may be turned off while we were waiting
+        if (isAccessibilityEnabled(source)) {
+            mLastSendTimeMillis = SystemClock.uptimeMillis();
+            performSendEvent(source);
+        }
+        resetStateInternal();
+    };
+
+    /**
+     * Populate and send an {@link AccessibilityEvent} using the given {@code source} view, as well
+     * as any extra data from this instance's state.
+     *
+     * Send the event via {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)} or
+     * {@link View#sendAccessibilityEvent(int)} on the provided {@code source} view to allow for
+     * overrides of those methods on {@link View} subclasses to take effect, and/or make sure that
+     * an {@link View#getAccessibilityDelegate() accessibility delegate} is not ignored if any.
+     */
+    protected abstract void performSendEvent(@NonNull View source);
+
+    /**
+     * Perform optional cleanup after {@link #performSendEvent}
+     *
+     * @param source the view this event was associated with
+     */
+    protected abstract void resetState(@Nullable View source);
+
+    /**
+     * Attempt to merge the pending events for source views {@code oldSource} and {@code newSource}
+     * into one, with source set to the resulting {@link View}
+     *
+     * A result of {@code null} means merger is not possible, resulting in the currently pending
+     * event being flushed before proceeding.
+     */
+    protected @Nullable View tryMerge(@NonNull View oldSource, @NonNull View newSource) {
+        return null;
+    }
+
+    /**
+     * Schedules a {@link #performSendEvent} with the source {@link View} set to given
+     * {@code source}
+     *
+     * If an event is already scheduled a {@link #tryMerge merge} will be attempted.
+     * If merging is not possible (as indicated by the null result from {@link #tryMerge}),
+     * the currently scheduled event will be {@link #sendNow sent immediately} and the new one
+     * will be scheduled afterwards.
+     */
+    protected final void scheduleFor(@NonNull View source) {
+        if (DEBUG) Log.d(LOG_TAG, thisClass() + ".scheduleFor(source = " + source + ")");
+
+        Handler uiHandler = source.getHandler();
+        if (uiHandler == null || uiHandler.getLooper() != Looper.myLooper()) {
+            CalledFromWrongThreadException e = new CalledFromWrongThreadException(
+                    "Expected to be called from main thread but was called from "
+                            + Thread.currentThread());
+            // TODO: Throw the exception
+            Log.e(LOG_TAG, "Accessibility content change on non-UI thread. Future Android "
+                    + "versions will throw an exception.", e);
+        }
+
+        if (!isAccessibilityEnabled(source)) return;
+
+        if (mIsPending) {
+            View merged = tryMerge(mSource, source);
+            if (merged != null) {
+                setSource(merged);
+                return;
+            } else {
+                sendNow();
+            }
+        }
+
+        setSource(source);
+
+        final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastSendTimeMillis;
+        final long minEventIntervalMillis =
+                ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
+        if (timeSinceLastMillis >= minEventIntervalMillis) {
+            sendNow();
+        } else {
+            mSource.postDelayed(mWorker, minEventIntervalMillis - timeSinceLastMillis);
+        }
+    }
+
+    static boolean isAccessibilityEnabled(@NonNull View contextProvider) {
+        return AccessibilityManager.getInstance(contextProvider.getContext()).isEnabled();
+    }
+
+    protected final void sendNow(View source) {
+        setSource(source);
+        sendNow();
+    }
+
+    private void sendNow() {
+        mSource.removeCallbacks(mWorker);
+        mWorker.run();
+    }
+
+    /**
+     * Flush the event if one is pending
+     */
+    public void sendNowIfPending() {
+        if (mIsPending) sendNow();
+    }
+
+    /**
+     * Cancel the event if one is pending and is for the given view
+     */
+    public final void cancelIfPendingFor(@NonNull View source) {
+        if (isPendingFor(source)) cancelIfPending(this);
+    }
+
+    /**
+     * @return whether an event is currently pending for the given source view
+     */
+    protected final boolean isPendingFor(@Nullable View source) {
+        return mIsPending && mSource == source;
+    }
+
+    /**
+     * Cancel the event if one is not null and pending
+     */
+    public static void cancelIfPending(@Nullable ThrottlingAccessibilityEventSender sender) {
+        if (sender == null || !sender.checkAndResetIsPending()) return;
+        sender.mSource.removeCallbacks(sender.mWorker);
+        sender.resetStateInternal();
+    }
+
+    void resetStateInternal() {
+        if (DEBUG) Log.d(LOG_TAG, thisClass() + ".resetStateInternal()");
+
+        resetState(mSource);
+        setSource(null);
+    }
+
+    boolean checkAndResetIsPending() {
+        if (mIsPending) {
+            mIsPending = false;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private void setSource(@Nullable View source) {
+        if (DEBUG) Log.d(LOG_TAG, thisClass() + ".setSource(" + source + ")");
+
+        if (source == null && mIsPending) {
+            Log.e(LOG_TAG, "mSource nullified while callback still pending: " + this);
+            return;
+        }
+
+        if (source != null && !mIsPending) {
+            // At most one can be pending at any given time
+            View oldSource = mSource;
+            if (oldSource != null) {
+                ViewRootImpl viewRootImpl = oldSource.getViewRootImpl();
+                if (viewRootImpl != null) {
+                    viewRootImpl.flushPendingAccessibilityEvents();
+                }
+            }
+            mIsPending = true;
+        }
+        mSource = source;
+    }
+
+    String thisClass() {
+        return getClass().getSimpleName();
+    }
+
+    @Override
+    public String toString() {
+        return thisClass() + "(" + mSource + ")";
+    }
+
+}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 57f9895..e554540 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -1,17 +1,17 @@
 /*
- * Copyright (C) 2007-2008 The Android Open Source Project
+ * Copyright (C) 2007 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this 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, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package android.view.inputmethod;
@@ -131,13 +131,13 @@
      * spans. <strong>Editor authors</strong>: you should strive to
      * send text with styles if possible, but it is not required.
      */
-    static final int GET_TEXT_WITH_STYLES = 0x0001;
+    int GET_TEXT_WITH_STYLES = 0x0001;
 
     /**
      * Flag for use with {@link #getExtractedText} to indicate you
      * would like to receive updates when the extracted text changes.
      */
-    public static final int GET_EXTRACTED_TEXT_MONITOR = 0x0001;
+    int GET_EXTRACTED_TEXT_MONITOR = 0x0001;
 
     /**
      * Get <var>n</var> characters of text before the current cursor
@@ -176,7 +176,7 @@
      * @return the text before the cursor position; the length of the
      * returned text might be less than <var>n</var>.
      */
-    public CharSequence getTextBeforeCursor(int n, int flags);
+    CharSequence getTextBeforeCursor(int n, int flags);
 
     /**
      * Get <var>n</var> characters of text after the current cursor
@@ -215,7 +215,7 @@
      * @return the text after the cursor position; the length of the
      * returned text might be less than <var>n</var>.
      */
-    public CharSequence getTextAfterCursor(int n, int flags);
+    CharSequence getTextAfterCursor(int n, int flags);
 
     /**
      * Gets the selected text, if any.
@@ -249,7 +249,7 @@
      * later, returns false when the target application does not implement
      * this method.
      */
-    public CharSequence getSelectedText(int flags);
+    CharSequence getSelectedText(int flags);
 
     /**
      * Retrieve the current capitalization mode in effect at the
@@ -279,7 +279,7 @@
      * @return the caps mode flags that are in effect at the current
      * cursor position. See TYPE_TEXT_FLAG_CAPS_* in {@link android.text.InputType}.
      */
-    public int getCursorCapsMode(int reqModes);
+    int getCursorCapsMode(int reqModes);
 
     /**
      * Retrieve the current text in the input connection's editor, and
@@ -314,8 +314,7 @@
      * longer valid of the editor can't comply with the request for
      * some reason.
      */
-    public ExtractedText getExtractedText(ExtractedTextRequest request,
-            int flags);
+    ExtractedText getExtractedText(ExtractedTextRequest request, int flags);
 
     /**
      * Delete <var>beforeLength</var> characters of text before the
@@ -342,8 +341,8 @@
      * delete more characters than are in the editor, as that may have
      * ill effects on the application. Calling this method will cause
      * the editor to call
-     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, int, int)}
-     * on your service after the batch input is over.</p>
+     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+     * int, int)} on your service after the batch input is over.</p>
      *
      * <p><strong>Editor authors:</strong> please be careful of race
      * conditions in implementing this call. An IME can make a change
@@ -369,7 +368,7 @@
      *        that range.
      * @return true on success, false if the input connection is no longer valid.
      */
-    public boolean deleteSurroundingText(int beforeLength, int afterLength);
+    boolean deleteSurroundingText(int beforeLength, int afterLength);
 
     /**
      * A variant of {@link #deleteSurroundingText(int, int)}. Major differences are:
@@ -397,7 +396,7 @@
      * @return true on success, false if the input connection is no longer valid.  Returns
      * {@code false} when the target application does not implement this method.
      */
-    public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
+    boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
 
     /**
      * Replace the currently composing text with the given text, and
@@ -416,8 +415,8 @@
      * <p>This is usually called by IMEs to add or remove or change
      * characters in the composing span. Calling this method will
      * cause the editor to call
-     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, int, int)}
-     * on the current IME after the batch input is over.</p>
+     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+     * int, int)} on the current IME after the batch input is over.</p>
      *
      * <p><strong>Editor authors:</strong> please keep in mind the
      * text may be very similar or completely different than what was
@@ -455,7 +454,7 @@
      * @return true on success, false if the input connection is no longer
      * valid.
      */
-    public boolean setComposingText(CharSequence text, int newCursorPosition);
+    boolean setComposingText(CharSequence text, int newCursorPosition);
 
     /**
      * Mark a certain region of text as composing text. If there was a
@@ -474,8 +473,8 @@
      * <p>Since this does not change the contents of the text, editors should not call
      * {@link InputMethodManager#updateSelection(View, int, int, int, int)} and
      * IMEs should not receive
-     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, int, int)}.
-     * </p>
+     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+     * int, int)}.</p>
      *
      * <p>This has no impact on the cursor/selection position. It may
      * result in the cursor being anywhere inside or outside the
@@ -488,7 +487,7 @@
      * valid. In {@link android.os.Build.VERSION_CODES#N} and later, false is returned when the
      * target application does not implement this method.
      */
-    public boolean setComposingRegion(int start, int end);
+    boolean setComposingRegion(int start, int end);
 
     /**
      * Have the text editor finish whatever composing text is
@@ -507,7 +506,7 @@
      * @return true on success, false if the input connection
      * is no longer valid.
      */
-    public boolean finishComposingText();
+    boolean finishComposingText();
 
     /**
      * Commit text to the text box and set the new cursor position.
@@ -522,8 +521,8 @@
      * then {@link #finishComposingText()}.</p>
      *
      * <p>Calling this method will cause the editor to call
-     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, int, int)}
-     * on the current IME after the batch input is over.
+     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+     * int, int)} on the current IME after the batch input is over.
      * <strong>Editor authors</strong>, for this to happen you need to
      * make the changes known to the input method by calling
      * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
@@ -543,7 +542,7 @@
      * @return true on success, false if the input connection is no longer
      * valid.
      */
-    public boolean commitText(CharSequence text, int newCursorPosition);
+    boolean commitText(CharSequence text, int newCursorPosition);
 
     /**
      * Commit a completion the user has selected from the possible ones
@@ -569,8 +568,8 @@
      *
      * <p>Calling this method (with a valid {@link CompletionInfo} object)
      * will cause the editor to call
-     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, int, int)}
-     * on the current IME after the batch input is over.
+     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+     * int, int)} on the current IME after the batch input is over.
      * <strong>Editor authors</strong>, for this to happen you need to
      * make the changes known to the input method by calling
      * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
@@ -581,15 +580,15 @@
      * @return true on success, false if the input connection is no longer
      * valid.
      */
-    public boolean commitCompletion(CompletionInfo text);
+    boolean commitCompletion(CompletionInfo text);
 
     /**
      * Commit a correction automatically performed on the raw user's input. A
      * typical example would be to correct typos using a dictionary.
      *
      * <p>Calling this method will cause the editor to call
-     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, int, int)}
-     * on the current IME after the batch input is over.
+     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+     * int, int)} on the current IME after the batch input is over.
      * <strong>Editor authors</strong>, for this to happen you need to
      * make the changes known to the input method by calling
      * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
@@ -601,7 +600,7 @@
      * In {@link android.os.Build.VERSION_CODES#N} and later, returns false
      * when the target application does not implement this method.
      */
-    public boolean commitCorrection(CorrectionInfo correctionInfo);
+    boolean commitCorrection(CorrectionInfo correctionInfo);
 
     /**
      * Set the selection of the text editor. To set the cursor
@@ -609,8 +608,8 @@
      *
      * <p>Since this moves the cursor, calling this method will cause
      * the editor to call
-     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, int, int)}
-     * on the current IME after the batch input is over.
+     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+     * int, int)} on the current IME after the batch input is over.
      * <strong>Editor authors</strong>, for this to happen you need to
      * make the changes known to the input method by calling
      * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
@@ -628,7 +627,7 @@
      * @return true on success, false if the input connection is no longer
      * valid.
      */
-    public boolean setSelection(int start, int end);
+    boolean setSelection(int start, int end);
 
     /**
      * Have the editor perform an action it has said it can do.
@@ -642,7 +641,7 @@
      * @return true on success, false if the input connection is no longer
      * valid.
      */
-    public boolean performEditorAction(int editorAction);
+    boolean performEditorAction(int editorAction);
 
     /**
      * Perform a context menu action on the field. The given id may be one of:
@@ -652,7 +651,7 @@
      * {@link android.R.id#paste}, {@link android.R.id#copyUrl},
      * or {@link android.R.id#switchInputMethod}
      */
-    public boolean performContextMenuAction(int id);
+    boolean performContextMenuAction(int id);
 
     /**
      * Tell the editor that you are starting a batch of editor
@@ -662,8 +661,8 @@
      *
      * <p><strong>IME authors:</strong> use this to avoid getting
      * calls to
-     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, int, int)}
-     * corresponding to intermediate state. Also, use this to avoid
+     * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+     * int, int)} corresponding to intermediate state. Also, use this to avoid
      * flickers that may arise from displaying intermediate state. Be
      * sure to call {@link #endBatchEdit} for each call to this, or
      * you may block updates in the editor.</p>
@@ -678,7 +677,7 @@
      * this method starts a batch edit, that means it will always return true
      * unless the input connection is no longer valid.
      */
-    public boolean beginBatchEdit();
+    boolean beginBatchEdit();
 
     /**
      * Tell the editor that you are done with a batch edit previously
@@ -696,7 +695,7 @@
      * the latest one (in other words, if the nesting count is > 0), false
      * otherwise or if the input connection is no longer valid.
      */
-    public boolean endBatchEdit();
+    boolean endBatchEdit();
 
     /**
      * Send a key event to the process that is currently attached
@@ -734,7 +733,7 @@
      * @see KeyCharacterMap#PREDICTIVE
      * @see KeyCharacterMap#ALPHA
      */
-    public boolean sendKeyEvent(KeyEvent event);
+    boolean sendKeyEvent(KeyEvent event);
 
     /**
      * Clear the given meta key pressed states in the given input
@@ -749,7 +748,7 @@
      * @return true on success, false if the input connection is no longer
      * valid.
      */
-    public boolean clearMetaKeyStates(int states);
+    boolean clearMetaKeyStates(int states);
 
     /**
      * Called back when the connected IME switches between fullscreen and normal modes.
@@ -766,7 +765,7 @@
      *         devices.
      * @see InputMethodManager#isFullscreenMode()
      */
-    public boolean reportFullscreenMode(boolean enabled);
+    boolean reportFullscreenMode(boolean enabled);
 
     /**
      * API to send private commands from an input method to its
@@ -786,7 +785,7 @@
      * associated editor understood it), false if the input connection is no longer
      * valid.
      */
-    public boolean performPrivateCommand(String action, Bundle data);
+    boolean performPrivateCommand(String action, Bundle data);
 
     /**
      * The editor is requested to call
@@ -794,7 +793,7 @@
      * once, as soon as possible, regardless of cursor/anchor position changes. This flag can be
      * used together with {@link #CURSOR_UPDATE_MONITOR}.
      */
-    public static final int CURSOR_UPDATE_IMMEDIATE = 1 << 0;
+    int CURSOR_UPDATE_IMMEDIATE = 1 << 0;
 
     /**
      * The editor is requested to call
@@ -805,7 +804,7 @@
      * This flag can be used together with {@link #CURSOR_UPDATE_IMMEDIATE}.
      * </p>
      */
-    public static final int CURSOR_UPDATE_MONITOR = 1 << 1;
+    int CURSOR_UPDATE_MONITOR = 1 << 1;
 
     /**
      * Called by the input method to ask the editor for calling back
@@ -821,7 +820,7 @@
      * In {@link android.os.Build.VERSION_CODES#N} and later, returns {@code false} also when the
      * target application does not implement this method.
      */
-    public boolean requestCursorUpdates(int cursorUpdateMode);
+    boolean requestCursorUpdates(int cursorUpdateMode);
 
     /**
      * Called by the {@link InputMethodManager} to enable application developers to specify a
@@ -832,7 +831,7 @@
      *
      * @return {@code null} to use the default {@link Handler}.
      */
-    public Handler getHandler();
+    Handler getHandler();
 
     /**
      * Called by the system up to only once to notify that the system is about to invalidate
@@ -846,7 +845,7 @@
      *
      * <p>Note: This does nothing when called from input methods.</p>
      */
-    public void closeConnection();
+    void closeConnection();
 
     /**
      * When this flag is used, the editor will be able to request read access to the content URI
@@ -863,7 +862,7 @@
      * client is able to request a temporary read-only access even after the current IME is switched
      * to any other IME as long as the client keeps {@link InputContentInfo} object.</p>
      **/
-    public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION =
+    int INPUT_CONTENT_GRANT_READ_URI_PERMISSION =
             android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;  // 0x00000001
 
     /**
@@ -897,6 +896,6 @@
      * @return {@code true} if this request is accepted by the application, whether the request
      * is already handled or still being handled in background, {@code false} otherwise.
      */
-    public boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
+    boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
             @Nullable Bundle opts);
 }
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 317730c..f671e22 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -1,17 +1,17 @@
 /*
- * Copyright (C) 2007-2008 The Android Open Source Project
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
  * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package android.view.inputmethod;
@@ -74,6 +74,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public CharSequence getTextBeforeCursor(int n, int flags) {
         return mTarget.getTextBeforeCursor(n, flags);
     }
@@ -82,6 +83,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public CharSequence getTextAfterCursor(int n, int flags) {
         return mTarget.getTextAfterCursor(n, flags);
     }
@@ -90,6 +92,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public CharSequence getSelectedText(int flags) {
         return mTarget.getSelectedText(flags);
     }
@@ -98,6 +101,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public int getCursorCapsMode(int reqModes) {
         return mTarget.getCursorCapsMode(reqModes);
     }
@@ -106,6 +110,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
         return mTarget.getExtractedText(request, flags);
     }
@@ -114,6 +119,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
         return mTarget.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
     }
@@ -122,6 +128,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         return mTarget.deleteSurroundingText(beforeLength, afterLength);
     }
@@ -130,6 +137,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
         return mTarget.setComposingText(text, newCursorPosition);
     }
@@ -138,6 +146,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean setComposingRegion(int start, int end) {
         return mTarget.setComposingRegion(start, end);
     }
@@ -146,6 +155,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean finishComposingText() {
         return mTarget.finishComposingText();
     }
@@ -154,6 +164,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean commitText(CharSequence text, int newCursorPosition) {
         return mTarget.commitText(text, newCursorPosition);
     }
@@ -162,6 +173,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean commitCompletion(CompletionInfo text) {
         return mTarget.commitCompletion(text);
     }
@@ -170,6 +182,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean commitCorrection(CorrectionInfo correctionInfo) {
         return mTarget.commitCorrection(correctionInfo);
     }
@@ -178,6 +191,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean setSelection(int start, int end) {
         return mTarget.setSelection(start, end);
     }
@@ -186,6 +200,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean performEditorAction(int editorAction) {
         return mTarget.performEditorAction(editorAction);
     }
@@ -194,6 +209,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean performContextMenuAction(int id) {
         return mTarget.performContextMenuAction(id);
     }
@@ -202,6 +218,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean beginBatchEdit() {
         return mTarget.beginBatchEdit();
     }
@@ -210,6 +227,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean endBatchEdit() {
         return mTarget.endBatchEdit();
     }
@@ -218,6 +236,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean sendKeyEvent(KeyEvent event) {
         return mTarget.sendKeyEvent(event);
     }
@@ -226,6 +245,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean clearMetaKeyStates(int states) {
         return mTarget.clearMetaKeyStates(states);
     }
@@ -234,6 +254,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean reportFullscreenMode(boolean enabled) {
         return mTarget.reportFullscreenMode(enabled);
     }
@@ -242,6 +263,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean performPrivateCommand(String action, Bundle data) {
         return mTarget.performPrivateCommand(action, data);
     }
@@ -250,6 +272,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean requestCursorUpdates(int cursorUpdateMode) {
         return mTarget.requestCursorUpdates(cursorUpdateMode);
     }
@@ -258,6 +281,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public Handler getHandler() {
         return mTarget.getHandler();
     }
@@ -266,6 +290,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public void closeConnection() {
         mTarget.closeConnection();
     }
@@ -274,6 +299,7 @@
      * {@inheritDoc}
      * @throws NullPointerException if the target is {@code null}.
      */
+    @Override
     public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
         return mTarget.commitContent(inputContentInfo, flags, opts);
     }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 80d7b6b7..7db5c32 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -337,20 +337,23 @@
     int mCursorCandEnd;
 
     /**
-     * Represents an invalid action notification sequence number. {@link InputMethodManagerService}
-     * always issues a positive integer for action notification sequence numbers. Thus -1 is
-     * guaranteed to be different from any valid sequence number.
+     * Represents an invalid action notification sequence number.
+     * {@link com.android.server.InputMethodManagerService} always issues a positive integer for
+     * action notification sequence numbers. Thus {@code -1} is guaranteed to be different from any
+     * valid sequence number.
      */
     private static final int NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER = -1;
     /**
-     * The next sequence number that is to be sent to {@link InputMethodManagerService} via
+     * The next sequence number that is to be sent to
+     * {@link com.android.server.InputMethodManagerService} via
      * {@link IInputMethodManager#notifyUserAction(int)} at once when a user action is observed.
      */
     private int mNextUserActionNotificationSequenceNumber =
             NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
 
     /**
-     * The last sequence number that is already sent to {@link InputMethodManagerService}.
+     * The last sequence number that is already sent to
+     * {@link com.android.server.InputMethodManagerService}.
      */
     private int mLastSentUserActionNotificationSequenceNumber =
             NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
@@ -1079,15 +1082,15 @@
     }
 
     /**
-     * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
-     * input window should only be hidden if it was not explicitly shown
+     * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestHideSelf(int)}
+     * to indicate that the soft input window should only be hidden if it was not explicitly shown
      * by the user.
      */
     public static final int HIDE_IMPLICIT_ONLY = 0x0001;
 
     /**
-     * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
-     * input window should normally be hidden, unless it was originally
+     * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestShowSelf(int)}
+     * to indicate that the soft input window should normally be hidden, unless it was originally
      * shown with {@link #SHOW_FORCED}.
      */
     public static final int HIDE_NOT_ALWAYS = 0x0002;
@@ -1255,12 +1258,7 @@
             // The view is running on a different thread than our own, so
             // we need to reschedule our work for over there.
             if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
-            vh.post(new Runnable() {
-                @Override
-                public void run() {
-                    startInputInner(startInputReason, null, 0, 0, 0);
-                }
-            });
+            vh.post(() -> startInputInner(startInputReason, null, 0, 0, 0));
             return false;
         }
 
@@ -1871,9 +1869,9 @@
      * @param flags Provides additional operating flags.  Currently may be
      * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
      * {@link #HIDE_NOT_ALWAYS} bit set.
-     * @deprecated Use {@link InputMethodService#hideSoftInputFromInputMethod(int)}
-     * instead. This method was intended for IME developers who should be accessing APIs through
-     * the service. APIs in this class are intended for app developers interacting with the IME.
+     * @deprecated Use {@link InputMethodService#requestHideSelf(int)} instead. This method was
+     * intended for IME developers who should be accessing APIs through the service. APIs in this
+     * class are intended for app developers interacting with the IME.
      */
     @Deprecated
     public void hideSoftInputFromInputMethod(IBinder token, int flags) {
@@ -1903,9 +1901,9 @@
      * @param flags Provides additional operating flags.  Currently may be
      * 0 or have the {@link #SHOW_IMPLICIT} or
      * {@link #SHOW_FORCED} bit set.
-     * @deprecated Use {@link InputMethodService#showSoftInputFromInputMethod(int)}
-     * instead. This method was intended for IME developers who should be accessing APIs through
-     * the service. APIs in this class are intended for app developers interacting with the IME.
+     * @deprecated Use {@link InputMethodService#requestShowSelf(int)} instead. This method was
+     * intended for IME developers who should be accessing APIs through the service. APIs in this
+     * class are intended for app developers interacting with the IME.
      */
     @Deprecated
     public void showSoftInputFromInputMethod(IBinder token, int flags) {
@@ -2429,8 +2427,8 @@
      * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
      * permission to the content.
      *
-     * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo, EditorInfo)}
-     * for details.</p>
+     * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo,
+     * InputConnection)} for details.</p>
      *
      * @param token Supplies the identifying token given to an input method when it was started,
      * which allows it to perform this operation on itself.
diff --git a/core/java/android/view/textclassifier/EntityConfidence.java b/core/java/android/view/textclassifier/EntityConfidence.java
index 19660d9..69a59a5 100644
--- a/core/java/android/view/textclassifier/EntityConfidence.java
+++ b/core/java/android/view/textclassifier/EntityConfidence.java
@@ -18,6 +18,8 @@
 
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.ArrayMap;
 
 import com.android.internal.util.Preconditions;
@@ -30,17 +32,16 @@
 /**
  * Helper object for setting and getting entity scores for classified text.
  *
- * @param <T> the entity type.
  * @hide
  */
-final class EntityConfidence<T> {
+final class EntityConfidence implements Parcelable {
 
-    private final ArrayMap<T, Float> mEntityConfidence = new ArrayMap<>();
-    private final ArrayList<T> mSortedEntities = new ArrayList<>();
+    private final ArrayMap<String, Float> mEntityConfidence = new ArrayMap<>();
+    private final ArrayList<String> mSortedEntities = new ArrayList<>();
 
     EntityConfidence() {}
 
-    EntityConfidence(@NonNull EntityConfidence<T> source) {
+    EntityConfidence(@NonNull EntityConfidence source) {
         Preconditions.checkNotNull(source);
         mEntityConfidence.putAll(source.mEntityConfidence);
         mSortedEntities.addAll(source.mSortedEntities);
@@ -54,24 +55,16 @@
      * @param source a map from entity to a confidence value in the range 0 (low confidence) to
      *               1 (high confidence).
      */
-    EntityConfidence(@NonNull Map<T, Float> source) {
+    EntityConfidence(@NonNull Map<String, Float> source) {
         Preconditions.checkNotNull(source);
 
         // Prune non-existent entities and clamp to 1.
         mEntityConfidence.ensureCapacity(source.size());
-        for (Map.Entry<T, Float> it : source.entrySet()) {
+        for (Map.Entry<String, Float> it : source.entrySet()) {
             if (it.getValue() <= 0) continue;
             mEntityConfidence.put(it.getKey(), Math.min(1, it.getValue()));
         }
-
-        // Create a list of entities sorted by decreasing confidence for getEntities().
-        mSortedEntities.ensureCapacity(mEntityConfidence.size());
-        mSortedEntities.addAll(mEntityConfidence.keySet());
-        mSortedEntities.sort((e1, e2) -> {
-            float score1 = mEntityConfidence.get(e1);
-            float score2 = mEntityConfidence.get(e2);
-            return Float.compare(score2, score1);
-        });
+        resetSortedEntitiesFromMap();
     }
 
     /**
@@ -79,7 +72,7 @@
      * high confidence to low confidence.
      */
     @NonNull
-    public List<T> getEntities() {
+    public List<String> getEntities() {
         return Collections.unmodifiableList(mSortedEntities);
     }
 
@@ -89,7 +82,7 @@
      * classified text.
      */
     @FloatRange(from = 0.0, to = 1.0)
-    public float getConfidenceScore(T entity) {
+    public float getConfidenceScore(String entity) {
         if (mEntityConfidence.containsKey(entity)) {
             return mEntityConfidence.get(entity);
         }
@@ -100,4 +93,51 @@
     public String toString() {
         return mEntityConfidence.toString();
     }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mEntityConfidence.size());
+        for (Map.Entry<String, Float> entry : mEntityConfidence.entrySet()) {
+            dest.writeString(entry.getKey());
+            dest.writeFloat(entry.getValue());
+        }
+    }
+
+    public static final Parcelable.Creator<EntityConfidence> CREATOR =
+            new Parcelable.Creator<EntityConfidence>() {
+                @Override
+                public EntityConfidence createFromParcel(Parcel in) {
+                    return new EntityConfidence(in);
+                }
+
+                @Override
+                public EntityConfidence[] newArray(int size) {
+                    return new EntityConfidence[size];
+                }
+            };
+
+    private EntityConfidence(Parcel in) {
+        final int numEntities = in.readInt();
+        mEntityConfidence.ensureCapacity(numEntities);
+        for (int i = 0; i < numEntities; ++i) {
+            mEntityConfidence.put(in.readString(), in.readFloat());
+        }
+        resetSortedEntitiesFromMap();
+    }
+
+    private void resetSortedEntitiesFromMap() {
+        mSortedEntities.clear();
+        mSortedEntities.ensureCapacity(mEntityConfidence.size());
+        mSortedEntities.addAll(mEntityConfidence.keySet());
+        mSortedEntities.sort((e1, e2) -> {
+            float score1 = mEntityConfidence.get(e1);
+            float score2 = mEntityConfidence.get(e2);
+            return Float.compare(score2, score1);
+        });
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 7ffbf63..7089677 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -22,8 +22,13 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.LocaleList;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.ArrayMap;
 import android.view.View.OnClickListener;
 import android.view.textclassifier.TextClassifier.EntityType;
@@ -52,7 +57,7 @@
  *   Button button = new Button(context);
  *   button.setCompoundDrawablesWithIntrinsicBounds(classification.getIcon(), null, null, null);
  *   button.setText(classification.getLabel());
- *   button.setOnClickListener(classification.getOnClickListener());
+ *   button.setOnClickListener(v -> context.startActivity(classification.getIntent()));
  * }</pre>
  *
  * <p>e.g. starting an action mode with menu items that can handle the classified text:
@@ -90,7 +95,6 @@
  *       ...
  *   });
  * }</pre>
- *
  */
 public final class TextClassification {
 
@@ -99,6 +103,10 @@
      */
     static final TextClassification EMPTY = new TextClassification.Builder().build();
 
+    // TODO(toki): investigate a way to derive this based on device properties.
+    private static final int MAX_PRIMARY_ICON_SIZE = 192;
+    private static final int MAX_SECONDARY_ICON_SIZE = 144;
+
     @NonNull private final String mText;
     @Nullable private final Drawable mPrimaryIcon;
     @Nullable private final String mPrimaryLabel;
@@ -107,8 +115,7 @@
     @NonNull private final List<Drawable> mSecondaryIcons;
     @NonNull private final List<String> mSecondaryLabels;
     @NonNull private final List<Intent> mSecondaryIntents;
-    @NonNull private final List<OnClickListener> mSecondaryOnClickListeners;
-    @NonNull private final EntityConfidence<String> mEntityConfidence;
+    @NonNull private final EntityConfidence mEntityConfidence;
     @NonNull private final String mSignature;
 
     private TextClassification(
@@ -120,12 +127,10 @@
             @NonNull List<Drawable> secondaryIcons,
             @NonNull List<String> secondaryLabels,
             @NonNull List<Intent> secondaryIntents,
-            @NonNull List<OnClickListener> secondaryOnClickListeners,
             @NonNull Map<String, Float> entityConfidence,
             @NonNull String signature) {
         Preconditions.checkArgument(secondaryLabels.size() == secondaryIntents.size());
         Preconditions.checkArgument(secondaryIcons.size() == secondaryIntents.size());
-        Preconditions.checkArgument(secondaryOnClickListeners.size() == secondaryIntents.size());
         mText = text;
         mPrimaryIcon = primaryIcon;
         mPrimaryLabel = primaryLabel;
@@ -134,8 +139,7 @@
         mSecondaryIcons = secondaryIcons;
         mSecondaryLabels = secondaryLabels;
         mSecondaryIntents = secondaryIntents;
-        mSecondaryOnClickListeners = secondaryOnClickListeners;
-        mEntityConfidence = new EntityConfidence<>(entityConfidence);
+        mEntityConfidence = new EntityConfidence(entityConfidence);
         mSignature = signature;
     }
 
@@ -186,7 +190,6 @@
      * @see #getSecondaryIntent(int)
      * @see #getSecondaryLabel(int)
      * @see #getSecondaryIcon(int)
-     * @see #getSecondaryOnClickListener(int)
      */
     @IntRange(from = 0)
     public int getSecondaryActionsCount() {
@@ -198,13 +201,10 @@
      * classified text.
      *
      * @param index Index of the action to get the icon for.
-     *
      * @throws IndexOutOfBoundsException if the specified index is out of range.
-     *
      * @see #getSecondaryActionsCount() for the number of actions available.
      * @see #getSecondaryIntent(int)
      * @see #getSecondaryLabel(int)
-     * @see #getSecondaryOnClickListener(int)
      * @see #getIcon()
      */
     @Nullable
@@ -228,13 +228,10 @@
      * the classified text.
      *
      * @param index Index of the action to get the label for.
-     *
      * @throws IndexOutOfBoundsException if the specified index is out of range.
-     *
      * @see #getSecondaryActionsCount()
      * @see #getSecondaryIntent(int)
      * @see #getSecondaryIcon(int)
-     * @see #getSecondaryOnClickListener(int)
      * @see #getLabel()
      */
     @Nullable
@@ -257,13 +254,10 @@
      * Returns one of the <i>secondary</i> intents that may be fired to act on the classified text.
      *
      * @param index Index of the action to get the intent for.
-     *
      * @throws IndexOutOfBoundsException if the specified index is out of range.
-     *
      * @see #getSecondaryActionsCount()
      * @see #getSecondaryLabel(int)
      * @see #getSecondaryIcon(int)
-     * @see #getSecondaryOnClickListener(int)
      * @see #getIntent()
      */
     @Nullable
@@ -282,29 +276,10 @@
     }
 
     /**
-     * Returns one of the <i>secondary</i> OnClickListeners that may be triggered to act on the
-     * classified text.
-     *
-     * @param index Index of the action to get the click listener for.
-     *
-     * @throws IndexOutOfBoundsException if the specified index is out of range.
-     *
-     * @see #getSecondaryActionsCount()
-     * @see #getSecondaryIntent(int)
-     * @see #getSecondaryLabel(int)
-     * @see #getSecondaryIcon(int)
-     * @see #getOnClickListener()
-     */
-    @Nullable
-    public OnClickListener getSecondaryOnClickListener(int index) {
-        return mSecondaryOnClickListeners.get(index);
-    }
-
-    /**
      * Returns the <i>primary</i> OnClickListener that may be triggered to act on the classified
-     * text.
-     *
-     * @see #getSecondaryOnClickListener(int)
+     * text. This field is not parcelable and will be null for all objects read from a parcel.
+     * Instead, call Context#startActivity(Intent) with the result of #getSecondaryIntent(int).
+     * Note that this may fail if the activity doesn't have permission to send the intent.
      */
     @Nullable
     public OnClickListener getOnClickListener() {
@@ -334,6 +309,42 @@
                 mSignature);
     }
 
+    /** Helper for parceling via #ParcelableWrapper. */
+    private void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mText);
+        final Bitmap primaryIconBitmap = drawableToBitmap(mPrimaryIcon, MAX_PRIMARY_ICON_SIZE);
+        dest.writeInt(primaryIconBitmap != null ? 1 : 0);
+        if (primaryIconBitmap != null) {
+            primaryIconBitmap.writeToParcel(dest, flags);
+        }
+        dest.writeString(mPrimaryLabel);
+        dest.writeInt(mPrimaryIntent != null ? 1 : 0);
+        if (mPrimaryIntent != null) {
+            mPrimaryIntent.writeToParcel(dest, flags);
+        }
+        // mPrimaryOnClickListener is not parcelable.
+        dest.writeTypedList(drawablesToBitmaps(mSecondaryIcons, MAX_SECONDARY_ICON_SIZE));
+        dest.writeStringList(mSecondaryLabels);
+        dest.writeTypedList(mSecondaryIntents);
+        mEntityConfidence.writeToParcel(dest, flags);
+        dest.writeString(mSignature);
+    }
+
+    /** Helper for unparceling via #ParcelableWrapper. */
+    private TextClassification(Parcel in) {
+        mText = in.readString();
+        mPrimaryIcon = in.readInt() == 0
+                ? null : new BitmapDrawable(null, Bitmap.CREATOR.createFromParcel(in));
+        mPrimaryLabel = in.readString();
+        mPrimaryIntent = in.readInt() == 0 ? null : Intent.CREATOR.createFromParcel(in);
+        mPrimaryOnClickListener = null;  // not parcelable
+        mSecondaryIcons = bitmapsToDrawables(in.createTypedArrayList(Bitmap.CREATOR));
+        mSecondaryLabels = in.createStringArrayList();
+        mSecondaryIntents = in.createTypedArrayList(Intent.CREATOR);
+        mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
+        mSignature = in.readString();
+    }
+
     /**
      * Creates an OnClickListener that starts an activity with the specified intent.
      *
@@ -349,6 +360,68 @@
     }
 
     /**
+     * Returns a Bitmap representation of the Drawable
+     *
+     * @param drawable The drawable to convert.
+     * @param maxDims The maximum edge length of the resulting bitmap (in pixels).
+     */
+    @Nullable
+    private static Bitmap drawableToBitmap(@Nullable Drawable drawable, int maxDims) {
+        if (drawable == null) {
+            return null;
+        }
+        final int actualWidth = Math.max(1, drawable.getIntrinsicWidth());
+        final int actualHeight = Math.max(1, drawable.getIntrinsicHeight());
+        final double scaleWidth = ((double) maxDims) / actualWidth;
+        final double scaleHeight = ((double) maxDims) / actualHeight;
+        final double scale = Math.min(1.0, Math.min(scaleWidth, scaleHeight));
+        final int width = (int) (actualWidth * scale);
+        final int height = (int) (actualHeight * scale);
+        if (drawable instanceof BitmapDrawable) {
+            final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+            if (actualWidth != width || actualHeight != height) {
+                return Bitmap.createScaledBitmap(
+                        bitmapDrawable.getBitmap(), width, height, /*filter=*/false);
+            } else {
+                return bitmapDrawable.getBitmap();
+            }
+        } else {
+            final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            final Canvas canvas = new Canvas(bitmap);
+            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+            drawable.draw(canvas);
+            return bitmap;
+        }
+    }
+
+    /**
+     * Returns a list of drawables converted to Bitmaps
+     *
+     * @param drawables The drawables to convert.
+     * @param maxDims The maximum edge length of the resulting bitmaps (in pixels).
+     */
+    private static List<Bitmap> drawablesToBitmaps(List<Drawable> drawables, int maxDims) {
+        final List<Bitmap> bitmaps = new ArrayList<>(drawables.size());
+        for (Drawable drawable : drawables) {
+            bitmaps.add(drawableToBitmap(drawable, maxDims));
+        }
+        return bitmaps;
+    }
+
+    /** Returns a list of drawable wrappers for a list of bitmaps. */
+    private static List<Drawable> bitmapsToDrawables(List<Bitmap> bitmaps) {
+        final List<Drawable> drawables = new ArrayList<>(bitmaps.size());
+        for (Bitmap bitmap : bitmaps) {
+            if (bitmap != null) {
+                drawables.add(new BitmapDrawable(null, bitmap));
+            } else {
+                drawables.add(null);
+            }
+        }
+        return drawables;
+    }
+
+    /**
      * Builder for building {@link TextClassification} objects.
      *
      * <p>e.g.
@@ -358,9 +431,9 @@
      *          .setText(classifiedText)
      *          .setEntityType(TextClassifier.TYPE_EMAIL, 0.9)
      *          .setEntityType(TextClassifier.TYPE_OTHER, 0.1)
-     *          .setPrimaryAction(intent, label, icon, onClickListener)
-     *          .addSecondaryAction(intent1, label1, icon1, onClickListener1)
-     *          .addSecondaryAction(intent2, label2, icon2, onClickListener2)
+     *          .setPrimaryAction(intent, label, icon)
+     *          .addSecondaryAction(intent1, label1, icon1)
+     *          .addSecondaryAction(intent2, label2, icon2)
      *          .build();
      * }</pre>
      */
@@ -370,7 +443,6 @@
         @NonNull private final List<Drawable> mSecondaryIcons = new ArrayList<>();
         @NonNull private final List<String> mSecondaryLabels = new ArrayList<>();
         @NonNull private final List<Intent> mSecondaryIntents = new ArrayList<>();
-        @NonNull private final List<OnClickListener> mSecondaryOnClickListeners = new ArrayList<>();
         @NonNull private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
         @Nullable Drawable mPrimaryIcon;
         @Nullable String mPrimaryLabel;
@@ -413,16 +485,14 @@
          * <p><stong>Note: </stong> If all input parameters are set to null, this method will be a
          * no-op.
          *
-         * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
+         * @see #setPrimaryAction(Intent, String, Drawable)
          */
         public Builder addSecondaryAction(
-                @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon,
-                @Nullable OnClickListener onClickListener) {
-            if (intent != null || label != null || icon != null || onClickListener != null) {
+                @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon) {
+            if (intent != null || label != null || icon != null) {
                 mSecondaryIntents.add(intent);
                 mSecondaryLabels.add(label);
                 mSecondaryIcons.add(icon);
-                mSecondaryOnClickListeners.add(onClickListener);
             }
             return this;
         }
@@ -432,7 +502,6 @@
          */
         public Builder clearSecondaryActions() {
             mSecondaryIntents.clear();
-            mSecondaryOnClickListeners.clear();
             mSecondaryLabels.clear();
             mSecondaryIcons.clear();
             return this;
@@ -440,26 +509,23 @@
 
         /**
          * Sets the <i>primary</i> action that may be performed on the classified text. This is
-         * equivalent to calling {@code
-         * setIntent(intent).setLabel(label).setIcon(icon).setOnClickListener(onClickListener)}.
+         * equivalent to calling {@code setIntent(intent).setLabel(label).setIcon(icon)}.
          *
          * <p><strong>Note: </strong>If all input parameters are null, there will be no
          * <i>primary</i> action but there may still be <i>secondary</i> actions.
          *
-         * @see #addSecondaryAction(Intent, String, Drawable, OnClickListener)
+         * @see #addSecondaryAction(Intent, String, Drawable)
          */
         public Builder setPrimaryAction(
-                @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon,
-                @Nullable OnClickListener onClickListener) {
-            return setIntent(intent).setLabel(label).setIcon(icon)
-                    .setOnClickListener(onClickListener);
+                @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon) {
+            return setIntent(intent).setLabel(label).setIcon(icon);
         }
 
         /**
          * Sets the icon for the <i>primary</i> action that may be rendered on a widget used to act
          * on the classified text.
          *
-         * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
+         * @see #setPrimaryAction(Intent, String, Drawable)
          */
         public Builder setIcon(@Nullable Drawable icon) {
             mPrimaryIcon = icon;
@@ -470,7 +536,7 @@
          * Sets the label for the <i>primary</i> action that may be rendered on a widget used to
          * act on the classified text.
          *
-         * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
+         * @see #setPrimaryAction(Intent, String, Drawable)
          */
         public Builder setLabel(@Nullable String label) {
             mPrimaryLabel = label;
@@ -481,7 +547,7 @@
          * Sets the intent for the <i>primary</i> action that may be fired to act on the classified
          * text.
          *
-         * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
+         * @see #setPrimaryAction(Intent, String, Drawable)
          */
         public Builder setIntent(@Nullable Intent intent) {
             mPrimaryIntent = intent;
@@ -490,9 +556,8 @@
 
         /**
          * Sets the OnClickListener for the <i>primary</i> action that may be triggered to act on
-         * the classified text.
-         *
-         * @see #setPrimaryAction(Intent, String, Drawable, OnClickListener)
+         * the classified text. This field is not parcelable and will always be null when the
+         * object is read from a parcel.
          */
         public Builder setOnClickListener(@Nullable OnClickListener onClickListener) {
             mPrimaryOnClickListener = onClickListener;
@@ -515,10 +580,8 @@
         public TextClassification build() {
             return new TextClassification(
                     mText,
-                    mPrimaryIcon, mPrimaryLabel,
-                    mPrimaryIntent, mPrimaryOnClickListener,
-                    mSecondaryIcons, mSecondaryLabels,
-                    mSecondaryIntents, mSecondaryOnClickListeners,
+                    mPrimaryIcon, mPrimaryLabel, mPrimaryIntent, mPrimaryOnClickListener,
+                    mSecondaryIcons, mSecondaryLabels, mSecondaryIntents,
                     mEntityConfidence, mSignature);
         }
     }
@@ -526,9 +589,11 @@
     /**
      * Optional input parameters for generating TextClassification.
      */
-    public static final class Options {
+    public static final class Options implements Parcelable {
 
-        private LocaleList mDefaultLocales;
+        private @Nullable LocaleList mDefaultLocales;
+
+        public Options() {}
 
         /**
          * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
@@ -548,5 +613,80 @@
         public LocaleList getDefaultLocales() {
             return mDefaultLocales;
         }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mDefaultLocales != null ? 1 : 0);
+            if (mDefaultLocales != null) {
+                mDefaultLocales.writeToParcel(dest, flags);
+            }
+        }
+
+        public static final Parcelable.Creator<Options> CREATOR =
+                new Parcelable.Creator<Options>() {
+                    @Override
+                    public Options createFromParcel(Parcel in) {
+                        return new Options(in);
+                    }
+
+                    @Override
+                    public Options[] newArray(int size) {
+                        return new Options[size];
+                    }
+                };
+
+        private Options(Parcel in) {
+            if (in.readInt() > 0) {
+                mDefaultLocales = LocaleList.CREATOR.createFromParcel(in);
+            }
+        }
+    }
+
+    /**
+     * Parcelable wrapper for TextClassification objects.
+     * @hide
+     */
+    public static final class ParcelableWrapper implements Parcelable {
+
+        @NonNull private TextClassification mTextClassification;
+
+        public ParcelableWrapper(@NonNull TextClassification textClassification) {
+            Preconditions.checkNotNull(textClassification);
+            mTextClassification = textClassification;
+        }
+
+        @NonNull
+        public TextClassification getTextClassification() {
+            return mTextClassification;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mTextClassification.writeToParcel(dest, flags);
+        }
+
+        public static final Parcelable.Creator<ParcelableWrapper> CREATOR =
+                new Parcelable.Creator<ParcelableWrapper>() {
+                    @Override
+                    public ParcelableWrapper createFromParcel(Parcel in) {
+                        return new ParcelableWrapper(new TextClassification(in));
+                    }
+
+                    @Override
+                    public ParcelableWrapper[] newArray(int size) {
+                        return new ParcelableWrapper[size];
+                    }
+                };
+
     }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index ed60430..b602095 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -23,6 +23,8 @@
 import android.annotation.StringDef;
 import android.annotation.WorkerThread;
 import android.os.LocaleList;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.ArraySet;
 
 import com.android.internal.util.Preconditions;
@@ -305,7 +307,7 @@
      *
      * Configs are initially based on a predefined preset, and can be modified from there.
      */
-    final class EntityConfig {
+    final class EntityConfig implements Parcelable {
         private final @TextClassifier.EntityPreset int mEntityPreset;
         private final Collection<String> mExcludedEntityTypes;
         private final Collection<String> mIncludedEntityTypes;
@@ -355,6 +357,37 @@
             }
             return Collections.unmodifiableList(entities);
         }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mEntityPreset);
+            dest.writeStringList(new ArrayList<>(mExcludedEntityTypes));
+            dest.writeStringList(new ArrayList<>(mIncludedEntityTypes));
+        }
+
+        public static final Parcelable.Creator<EntityConfig> CREATOR =
+                new Parcelable.Creator<EntityConfig>() {
+                    @Override
+                    public EntityConfig createFromParcel(Parcel in) {
+                        return new EntityConfig(in);
+                    }
+
+                    @Override
+                    public EntityConfig[] newArray(int size) {
+                        return new EntityConfig[size];
+                    }
+                };
+
+        private EntityConfig(Parcel in) {
+            mEntityPreset = in.readInt();
+            mExcludedEntityTypes = new ArraySet<>(in.createStringArrayList());
+            mIncludedEntityTypes = new ArraySet<>(in.createStringArrayList());
+        }
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/TextClassifierConstants.java b/core/java/android/view/textclassifier/TextClassifierConstants.java
index 51e6168..00695b7 100644
--- a/core/java/android/view/textclassifier/TextClassifierConstants.java
+++ b/core/java/android/view/textclassifier/TextClassifierConstants.java
@@ -45,19 +45,24 @@
             "smart_selection_dark_launch";
     private static final String SMART_SELECTION_ENABLED_FOR_EDIT_TEXT =
             "smart_selection_enabled_for_edit_text";
+    private static final String SMART_LINKIFY_ENABLED =
+            "smart_linkify_enabled";
 
     private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
     private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;
+    private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
 
     /** Default settings. */
     static final TextClassifierConstants DEFAULT = new TextClassifierConstants();
 
     private final boolean mDarkLaunch;
     private final boolean mSuggestSelectionEnabledForEditableText;
+    private final boolean mSmartLinkifyEnabled;
 
     private TextClassifierConstants() {
         mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
         mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
+        mSmartLinkifyEnabled = SMART_LINKIFY_ENABLED_DEFAULT;
     }
 
     private TextClassifierConstants(@Nullable String settings) {
@@ -74,6 +79,9 @@
         mSuggestSelectionEnabledForEditableText = parser.getBoolean(
                 SMART_SELECTION_ENABLED_FOR_EDIT_TEXT,
                 SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT);
+        mSmartLinkifyEnabled = parser.getBoolean(
+                SMART_LINKIFY_ENABLED,
+                SMART_LINKIFY_ENABLED_DEFAULT);
     }
 
     static TextClassifierConstants loadFromString(String settings) {
@@ -87,4 +95,8 @@
     public boolean isSuggestSelectionEnabledForEditableText() {
         return mSuggestSelectionEnabledForEditableText;
     }
+
+    public boolean isSmartLinkifyEnabled() {
+        return mSmartLinkifyEnabled;
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index aea3cb0..7db0e76 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -32,7 +32,6 @@
 import android.provider.Settings;
 import android.text.util.Linkify;
 import android.util.Patterns;
-import android.view.View.OnClickListener;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
@@ -187,6 +186,11 @@
         Utils.validateInput(text);
         final String textString = text.toString();
         final TextLinks.Builder builder = new TextLinks.Builder(textString);
+
+        if (!getSettings().isSmartLinkifyEnabled()) {
+            return builder.build();
+        }
+
         try {
             final LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null;
             final Collection<String> entitiesToIdentify =
@@ -457,12 +461,10 @@
                     }
                 }
                 final String labelString = (label != null) ? label.toString() : null;
-                final OnClickListener onClickListener =
-                        TextClassification.createStartActivityOnClickListener(mContext, intent);
                 if (i == 0) {
-                    builder.setPrimaryAction(intent, labelString, icon, onClickListener);
+                    builder.setPrimaryAction(intent, labelString, icon);
                 } else {
-                    builder.addSecondaryAction(intent, labelString, icon, onClickListener);
+                    builder.addSecondaryAction(intent, labelString, icon);
                 }
             }
         }
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index 6c587cf..ba854e0 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -20,6 +20,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.LocaleList;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.text.SpannableString;
 import android.text.style.ClickableSpan;
 import android.view.View;
@@ -38,7 +40,7 @@
  * A collection of links, representing subsequences of text and the entity types (phone number,
  * address, url, etc) they may be.
  */
-public final class TextLinks {
+public final class TextLinks implements Parcelable {
     private final String mFullText;
     private final List<TextLink> mLinks;
 
@@ -83,11 +85,40 @@
         return true;
     }
 
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mFullText);
+        dest.writeTypedList(mLinks);
+    }
+
+    public static final Parcelable.Creator<TextLinks> CREATOR =
+            new Parcelable.Creator<TextLinks>() {
+                @Override
+                public TextLinks createFromParcel(Parcel in) {
+                    return new TextLinks(in);
+                }
+
+                @Override
+                public TextLinks[] newArray(int size) {
+                    return new TextLinks[size];
+                }
+            };
+
+    private TextLinks(Parcel in) {
+        mFullText = in.readString();
+        mLinks = in.createTypedArrayList(TextLink.CREATOR);
+    }
+
     /**
      * A link, identifying a substring of text and possible entity types for it.
      */
-    public static final class TextLink {
-        private final EntityConfidence<String> mEntityScores;
+    public static final class TextLink implements Parcelable {
+        private final EntityConfidence mEntityScores;
         private final String mOriginalText;
         private final int mStart;
         private final int mEnd;
@@ -105,7 +136,7 @@
             mOriginalText = originalText;
             mStart = start;
             mEnd = end;
-            mEntityScores = new EntityConfidence<>(entityScores);
+            mEntityScores = new EntityConfidence(entityScores);
         }
 
         /**
@@ -153,16 +184,51 @@
                 @TextClassifier.EntityType String entityType) {
             return mEntityScores.getConfidenceScore(entityType);
         }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mEntityScores.writeToParcel(dest, flags);
+            dest.writeString(mOriginalText);
+            dest.writeInt(mStart);
+            dest.writeInt(mEnd);
+        }
+
+        public static final Parcelable.Creator<TextLink> CREATOR =
+                new Parcelable.Creator<TextLink>() {
+                    @Override
+                    public TextLink createFromParcel(Parcel in) {
+                        return new TextLink(in);
+                    }
+
+                    @Override
+                    public TextLink[] newArray(int size) {
+                        return new TextLink[size];
+                    }
+                };
+
+        private TextLink(Parcel in) {
+            mEntityScores = EntityConfidence.CREATOR.createFromParcel(in);
+            mOriginalText = in.readString();
+            mStart = in.readInt();
+            mEnd = in.readInt();
+        }
     }
 
     /**
      * Optional input parameters for generating TextLinks.
      */
-    public static final class Options {
+    public static final class Options implements Parcelable {
 
         private LocaleList mDefaultLocales;
         private TextClassifier.EntityConfig mEntityConfig;
 
+        public Options() {}
+
         /**
          * @param defaultLocales ordered list of locale preferences that may be used to
          *                       disambiguate the provided text. If no locale preferences exist,
@@ -201,6 +267,45 @@
         public TextClassifier.EntityConfig getEntityConfig() {
             return mEntityConfig;
         }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mDefaultLocales != null ? 1 : 0);
+            if (mDefaultLocales != null) {
+                mDefaultLocales.writeToParcel(dest, flags);
+            }
+            dest.writeInt(mEntityConfig != null ? 1 : 0);
+            if (mEntityConfig != null) {
+                mEntityConfig.writeToParcel(dest, flags);
+            }
+        }
+
+        public static final Parcelable.Creator<Options> CREATOR =
+                new Parcelable.Creator<Options>() {
+                    @Override
+                    public Options createFromParcel(Parcel in) {
+                        return new Options(in);
+                    }
+
+                    @Override
+                    public Options[] newArray(int size) {
+                        return new Options[size];
+                    }
+                };
+
+        private Options(Parcel in) {
+            if (in.readInt() > 0) {
+                mDefaultLocales = LocaleList.CREATOR.createFromParcel(in);
+            }
+            if (in.readInt() > 0) {
+                mEntityConfig = TextClassifier.EntityConfig.CREATOR.createFromParcel(in);
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 25e9e7e..774d42d 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -21,6 +21,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.LocaleList;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.ArrayMap;
 import android.view.textclassifier.TextClassifier.EntityType;
 
@@ -36,7 +38,7 @@
 
     private final int mStartIndex;
     private final int mEndIndex;
-    @NonNull private final EntityConfidence<String> mEntityConfidence;
+    @NonNull private final EntityConfidence mEntityConfidence;
     @NonNull private final String mSignature;
 
     private TextSelection(
@@ -44,7 +46,7 @@
             @NonNull String signature) {
         mStartIndex = startIndex;
         mEndIndex = endIndex;
-        mEntityConfidence = new EntityConfidence<>(entityConfidence);
+        mEntityConfidence = new EntityConfidence(entityConfidence);
         mSignature = signature;
     }
 
@@ -110,6 +112,22 @@
                 mStartIndex, mEndIndex, mEntityConfidence, mSignature);
     }
 
+    /** Helper for parceling via #ParcelableWrapper. */
+    private void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mStartIndex);
+        dest.writeInt(mEndIndex);
+        mEntityConfidence.writeToParcel(dest, flags);
+        dest.writeString(mSignature);
+    }
+
+    /** Helper for unparceling via #ParcelableWrapper. */
+    private TextSelection(Parcel in) {
+        mStartIndex = in.readInt();
+        mEndIndex = in.readInt();
+        mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
+        mSignature = in.readString();
+    }
+
     /**
      * Builder used to build {@link TextSelection} objects.
      */
@@ -170,11 +188,13 @@
     /**
      * Optional input parameters for generating TextSelection.
      */
-    public static final class Options {
+    public static final class Options implements Parcelable {
 
-        private LocaleList mDefaultLocales;
+        private @Nullable LocaleList mDefaultLocales;
         private boolean mDarkLaunchAllowed;
 
+        public Options() {}
+
         /**
          * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
          *      the provided text. If no locale preferences exist, set this to null or an empty
@@ -216,5 +236,82 @@
         public boolean isDarkLaunchAllowed() {
             return mDarkLaunchAllowed;
         }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mDefaultLocales != null ? 1 : 0);
+            if (mDefaultLocales != null) {
+                mDefaultLocales.writeToParcel(dest, flags);
+            }
+            dest.writeInt(mDarkLaunchAllowed ? 1 : 0);
+        }
+
+        public static final Parcelable.Creator<Options> CREATOR =
+                new Parcelable.Creator<Options>() {
+                    @Override
+                    public Options createFromParcel(Parcel in) {
+                        return new Options(in);
+                    }
+
+                    @Override
+                    public Options[] newArray(int size) {
+                        return new Options[size];
+                    }
+                };
+
+        private Options(Parcel in) {
+            if (in.readInt() > 0) {
+                mDefaultLocales = LocaleList.CREATOR.createFromParcel(in);
+            }
+            mDarkLaunchAllowed = in.readInt() != 0;
+        }
+    }
+
+    /**
+     * Parcelable wrapper for TextSelection objects.
+     * @hide
+     */
+    public static final class ParcelableWrapper implements Parcelable {
+
+        @NonNull private TextSelection mTextSelection;
+
+        public ParcelableWrapper(@NonNull TextSelection textSelection) {
+            Preconditions.checkNotNull(textSelection);
+            mTextSelection = textSelection;
+        }
+
+        @NonNull
+        public TextSelection getTextSelection() {
+            return mTextSelection;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mTextSelection.writeToParcel(dest, flags);
+        }
+
+        public static final Parcelable.Creator<ParcelableWrapper> CREATOR =
+                new Parcelable.Creator<ParcelableWrapper>() {
+                    @Override
+                    public ParcelableWrapper createFromParcel(Parcel in) {
+                        return new ParcelableWrapper(new TextSelection(in));
+                    }
+
+                    @Override
+                    public ParcelableWrapper[] newArray(int size) {
+                        return new ParcelableWrapper[size];
+                    }
+                };
+
     }
 }
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index b3522ec..e9fe481 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -27,7 +27,6 @@
 import android.content.pm.Signature;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.StrictMode;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
 import android.util.ArraySet;
@@ -251,7 +250,6 @@
                         "WebView.disableWebView() was called: WebView is disabled");
             }
 
-            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
             try {
                 Class<WebViewFactoryProvider> providerClass = getProviderClass();
@@ -279,7 +277,6 @@
                 }
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
-                StrictMode.setThreadPolicy(oldPolicy);
             }
         }
     }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e0c897d..6bee58f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -6849,7 +6849,7 @@
             // detached and we do not allow detached views to fire accessibility
             // events. So we are announcing that the subtree changed giving a chance
             // to clients holding on to a view in this subtree to refresh it.
-            notifyViewAccessibilityStateChangedIfNeeded(
+            notifyAccessibilityStateChanged(
                     AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
 
             // Don't scrap views that have transient state.
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 6c19256..08374cb 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -1093,7 +1093,7 @@
             checkSelectionChanged();
         }
 
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        notifyAccessibilitySubtreeChanged();
     }
 
     /**
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 92bfd56..af01a3e 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -132,7 +132,7 @@
         if (mChecked != checked) {
             mChecked = checked;
             refreshDrawableState();
-            notifyViewAccessibilityStateChangedIfNeeded(
+            notifyAccessibilityStateChanged(
                     AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
     }
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 0762b15..e57f153 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -158,7 +158,7 @@
             mCheckedFromResource = false;
             mChecked = checked;
             refreshDrawableState();
-            notifyViewAccessibilityStateChangedIfNeeded(
+            notifyAccessibilityStateChanged(
                     AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
 
             // Avoid infinite recursions if setChecked() is called from a listener
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 05d18d1..247c806 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2095,14 +2095,7 @@
         if (!(mTextView.getText() instanceof Spannable)) {
             return;
         }
-        Spannable text = (Spannable) mTextView.getText();
         stopTextActionMode();
-        if (mTextView.isTextSelectable()) {
-            Selection.setSelection((Spannable) text, link.getStart(), link.getEnd());
-        } else {
-            //TODO: Nonselectable text
-        }
-
         getSelectionActionModeHelper().startLinkActionModeAsync(link);
     }
 
@@ -2179,7 +2172,8 @@
             return false;
         }
 
-        if (!checkField() || !mTextView.hasSelection()) {
+        if (actionMode != TextActionMode.TEXT_LINK
+                && (!checkField() || !mTextView.hasSelection())) {
             return false;
         }
 
@@ -4012,7 +4006,6 @@
             if (isValidAssistMenuItem(
                     textClassification.getIcon(),
                     textClassification.getLabel(),
-                    textClassification.getOnClickListener(),
                     textClassification.getIntent())) {
                 final MenuItem item = menu.add(
                         TextView.ID_ASSIST, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST,
@@ -4020,14 +4013,15 @@
                         .setIcon(textClassification.getIcon())
                         .setIntent(textClassification.getIntent());
                 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
-                mAssistClickHandlers.put(item, textClassification.getOnClickListener());
+                mAssistClickHandlers.put(
+                        item, TextClassification.createStartActivityOnClickListener(
+                                mTextView.getContext(), textClassification.getIntent()));
             }
             final int count = textClassification.getSecondaryActionsCount();
             for (int i = 0; i < count; i++) {
                 if (!isValidAssistMenuItem(
                         textClassification.getSecondaryIcon(i),
                         textClassification.getSecondaryLabel(i),
-                        textClassification.getSecondaryOnClickListener(i),
                         textClassification.getSecondaryIntent(i))) {
                     continue;
                 }
@@ -4038,7 +4032,9 @@
                         .setIcon(textClassification.getSecondaryIcon(i))
                         .setIntent(textClassification.getSecondaryIntent(i));
                 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-                mAssistClickHandlers.put(item, textClassification.getSecondaryOnClickListener(i));
+                mAssistClickHandlers.put(item,
+                        TextClassification.createStartActivityOnClickListener(
+                                mTextView.getContext(), textClassification.getSecondaryIntent(i)));
             }
         }
 
@@ -4054,10 +4050,9 @@
             }
         }
 
-        private boolean isValidAssistMenuItem(
-                Drawable icon, CharSequence label, OnClickListener onClick, Intent intent) {
+        private boolean isValidAssistMenuItem(Drawable icon, CharSequence label, Intent intent) {
             final boolean hasUi = icon != null || !TextUtils.isEmpty(label);
-            final boolean hasAction = onClick != null || isSupportedIntent(intent);
+            final boolean hasAction = isSupportedIntent(intent);
             return hasUi && hasAction;
         }
 
@@ -4632,7 +4627,7 @@
             return 0;
         }
 
-        protected final void showMagnifier() {
+        protected final void showMagnifier(@NonNull final MotionEvent event) {
             if (mMagnifier == null) {
                 return;
             }
@@ -4658,9 +4653,10 @@
 
             final Layout layout = mTextView.getLayout();
             final int lineNumber = layout.getLineForOffset(offset);
-            // Horizontally snap to character offset.
-            final float xPosInView = getHorizontal(mTextView.getLayout(), offset)
-                    + mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
+            // Horizontally move the magnifier smoothly.
+            final int[] textViewLocationOnScreen = new int[2];
+            mTextView.getLocationOnScreen(textViewLocationOnScreen);
+            final float xPosInView = event.getRawX() - textViewLocationOnScreen[0];
             // Vertically snap to middle of current line.
             final float yPosInView = (mTextView.getLayout().getLineTop(lineNumber)
                     + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f
@@ -4855,11 +4851,11 @@
                 case MotionEvent.ACTION_DOWN:
                     mDownPositionX = ev.getRawX();
                     mDownPositionY = ev.getRawY();
-                    showMagnifier();
+                    showMagnifier(ev);
                     break;
 
                 case MotionEvent.ACTION_MOVE:
-                    showMagnifier();
+                    showMagnifier(ev);
                     break;
 
                 case MotionEvent.ACTION_UP:
@@ -5213,11 +5209,11 @@
                     // re-engages the handle.
                     mTouchWordDelta = 0.0f;
                     mPrevX = UNSET_X_VALUE;
-                    showMagnifier();
+                    showMagnifier(event);
                     break;
 
                 case MotionEvent.ACTION_MOVE:
-                    showMagnifier();
+                    showMagnifier(event);
                     break;
 
                 case MotionEvent.ACTION_UP:
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 26dfcc2..310b170 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -32,6 +32,7 @@
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.View;
+import android.view.ViewParent;
 
 import com.android.internal.util.Preconditions;
 
@@ -44,6 +45,8 @@
     private static final int NONEXISTENT_PREVIOUS_CONFIG_VALUE = -1;
     // The view to which this magnifier is attached.
     private final View mView;
+    // The coordinates of the view in the surface.
+    private final int[] mViewCoordinatesInSurface;
     // The window containing the magnifier.
     private final PopupWindow mWindow;
     // The center coordinates of the window containing the magnifier.
@@ -87,6 +90,8 @@
                 com.android.internal.R.dimen.magnifier_height);
         mZoomScale = context.getResources().getFloat(
                 com.android.internal.R.dimen.magnifier_zoom_scale);
+        // The view's surface coordinates will not be updated until the magnifier is first shown.
+        mViewCoordinatesInSurface = new int[2];
 
         mWindow = new PopupWindow(context);
         mWindow.setContentView(content);
@@ -120,9 +125,34 @@
         configureCoordinates(xPosInView, yPosInView);
 
         // Clamp startX value to avoid distorting the rendering of the magnifier content.
-        final int startX = Math.max(0, Math.min(
+        // For this, we compute:
+        // - zeroScrollXInSurface: this is the start x of mView, where this is not masked by a
+        //                         potential scrolling container. For example, if mView is a
+        //                         TextView contained in a HorizontalScrollView,
+        //                         mViewCoordinatesInSurface will reflect the surface position of
+        //                         the first text character, rather than the position of the first
+        //                         visible one. Therefore, we need to add back the amount of
+        //                         scrolling from the parent containers.
+        // - actualWidth: similarly, the width of a View will be larger than its actually visible
+        //                width when it is contained in a scrolling container. We need to use
+        //                the minimum width of a scrolling container which contains this view.
+        int zeroScrollXInSurface = mViewCoordinatesInSurface[0];
+        int actualWidth = mView.getWidth();
+        ViewParent viewParent = mView.getParent();
+        while (viewParent instanceof View) {
+            final View container = (View) viewParent;
+            if (container.canScrollHorizontally(-1 /* left scroll */)
+                    || container.canScrollHorizontally(1 /* right scroll */)) {
+                zeroScrollXInSurface += container.getScrollX();
+                actualWidth = Math.min(actualWidth, container.getWidth()
+                        - container.getPaddingLeft() - container.getPaddingRight());
+            }
+            viewParent = viewParent.getParent();
+        }
+
+        final int startX = Math.max(zeroScrollXInSurface, Math.min(
                 mCenterZoomCoords.x - mBitmap.getWidth() / 2,
-                mView.getWidth() - mBitmap.getWidth()));
+                zeroScrollXInSurface + actualWidth - mBitmap.getWidth()));
         final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
 
         if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) {
@@ -169,10 +199,9 @@
             posX = xPosInView;
             posY = yPosInView;
         } else {
-            final int[] coordinatesInSurface = new int[2];
-            mView.getLocationInSurface(coordinatesInSurface);
-            posX = xPosInView + coordinatesInSurface[0];
-            posY = yPosInView + coordinatesInSurface[1];
+            mView.getLocationInSurface(mViewCoordinatesInSurface);
+            posX = xPosInView + mViewCoordinatesInSurface[0];
+            posY = yPosInView + mViewCoordinatesInSurface[1];
         }
 
         mCenterZoomCoords.x = Math.round(posX);
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 2c6466c..3bfa520 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -235,10 +235,13 @@
             @Editor.TextActionMode int actionMode, @Nullable SelectionResult result) {
         final CharSequence text = getText(mTextView);
         if (result != null && text instanceof Spannable
-                && (mTextView.isTextSelectable() || mTextView.isTextEditable())) {
+                && (mTextView.isTextSelectable()
+                    || mTextView.isTextEditable()
+                    || actionMode == Editor.TextActionMode.TEXT_LINK)) {
             // Do not change the selection if TextClassifier should be dark launched.
             if (!mTextView.getTextClassifier().getSettings().isDarkLaunch()) {
                 Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
+                mTextView.invalidate();
             }
             mTextClassification = result.mClassification;
         } else {
@@ -250,8 +253,17 @@
                     && (mTextView.isTextSelectable() || mTextView.isTextEditable())) {
                 controller.show();
             }
-            if (result != null && actionMode == Editor.TextActionMode.SELECTION) {
-                mSelectionTracker.onSmartSelection(result);
+            if (result != null) {
+                switch (actionMode) {
+                    case Editor.TextActionMode.SELECTION:
+                        mSelectionTracker.onSmartSelection(result);
+                        break;
+                    case Editor.TextActionMode.TEXT_LINK:
+                        mSelectionTracker.onLinkSelected(result);
+                        break;
+                    default:
+                        break;
+                }
             }
         }
         mEditor.setRestartActionModeOnNextRefresh(false);
@@ -486,12 +498,24 @@
          * Called when selection action mode is started and the results come from a classifier.
          */
         public void onSmartSelection(SelectionResult result) {
+            onClassifiedSelection(result);
+            mLogger.logSelectionModified(
+                    result.mStart, result.mEnd, result.mClassification, result.mSelection);
+        }
+
+        /**
+         * Called when link action mode is started and the classification comes from a classifier.
+         */
+        public void onLinkSelected(SelectionResult result) {
+            onClassifiedSelection(result);
+            // TODO: log (b/70246800)
+        }
+
+        private void onClassifiedSelection(SelectionResult result) {
             if (isSelectionStarted()) {
                 mSelectionStart = result.mStart;
                 mSelectionEnd = result.mEnd;
                 mAllowReset = mSelectionStart != mOriginalStart || mSelectionEnd != mOriginalEnd;
-                mLogger.logSelectionModified(
-                        result.mStart, result.mEnd, result.mClassification, result.mSelection);
             }
         }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ff374fa..8c4e422 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -77,8 +77,8 @@
 import android.text.InputFilter;
 import android.text.InputType;
 import android.text.Layout;
+import android.text.MeasuredText;
 import android.text.ParcelableSpan;
-import android.text.PremeasuredText;
 import android.text.Selection;
 import android.text.SpanWatcher;
 import android.text.Spannable;
@@ -2365,7 +2365,7 @@
         setText(mText);
 
         if (hasPasswordTransformationMethod()) {
-            notifyViewAccessibilityStateChangedIfNeeded(
+            notifyAccessibilityStateChanged(
                     AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
 
@@ -5393,7 +5393,7 @@
             if (imm != null) imm.restartInput(this);
         } else if (type == BufferType.SPANNABLE || mMovement != null) {
             text = mSpannableFactory.newSpannable(text);
-        } else if (!(text instanceof PremeasuredText || text instanceof CharWrapper)) {
+        } else if (!(text instanceof MeasuredText || text instanceof CharWrapper)) {
             text = TextUtils.stringOrSpannedString(text);
         }
 
@@ -5476,7 +5476,7 @@
         sendOnTextChanged(text, 0, oldlen, textLength);
         onTextChanged(text, 0, oldlen, textLength);
 
-        notifyViewAccessibilityStateChangedIfNeeded(AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
+        notifyAccessibilityStateChanged(AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
 
         if (needEditableForNotification) {
             sendAfterTextChanged((Editable) text);
@@ -6210,7 +6210,7 @@
     public void setError(CharSequence error, Drawable icon) {
         createEditorIfNeeded();
         mEditor.setError(error, icon);
-        notifyViewAccessibilityStateChangedIfNeeded(
+        notifyAccessibilityStateChanged(
                 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
     }
 
@@ -11011,6 +11011,12 @@
                 return true;
 
             case ID_COPY:
+                // For link action mode in a non-selectable/non-focusable TextView,
+                // make sure that we set the appropriate min/max.
+                final int selStart = getSelectionStart();
+                final int selEnd = getSelectionEnd();
+                min = Math.max(0, Math.min(selStart, selEnd));
+                max = Math.max(0, Math.max(selStart, selEnd));
                 final ClipData copyData = ClipData.newPlainText(null, getTransformedText(min, max));
                 if (setPrimaryClip(copyData)) {
                     stopTextActionMode();
@@ -11233,11 +11239,9 @@
      */
     public boolean requestActionMode(@NonNull TextLinks.TextLink link) {
         Preconditions.checkNotNull(link);
-        if (mEditor != null) {
-            mEditor.startLinkActionModeAsync(link);
-            return true;
-        }
-        return false;
+        createEditorIfNeeded();
+        mEditor.startLinkActionModeAsync(link);
+        return true;
     }
     /**
      * @hide
@@ -11952,7 +11956,7 @@
         private final Choreographer mChoreographer;
 
         private byte mStatus = MARQUEE_STOPPED;
-        private final float mPixelsPerSecond;
+        private final float mPixelsPerMs;
         private float mMaxScroll;
         private float mMaxFadeScroll;
         private float mGhostStart;
@@ -11965,7 +11969,7 @@
 
         Marquee(TextView v) {
             final float density = v.getContext().getResources().getDisplayMetrics().density;
-            mPixelsPerSecond = MARQUEE_DP_PER_SECOND * density;
+            mPixelsPerMs = MARQUEE_DP_PER_SECOND * density / 1000f;
             mView = new WeakReference<TextView>(v);
             mChoreographer = Choreographer.getInstance();
         }
@@ -12010,7 +12014,7 @@
                 long currentMs = mChoreographer.getFrameTime();
                 long deltaMs = currentMs - mLastAnimationMs;
                 mLastAnimationMs = currentMs;
-                float deltaPx = deltaMs / 1000f * mPixelsPerSecond;
+                float deltaPx = deltaMs * mPixelsPerMs;
                 mScroll += deltaPx;
                 if (mScroll > mMaxScroll) {
                     mScroll = mMaxScroll;
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
new file mode 100644
index 0000000..310a7bb
--- /dev/null
+++ b/core/java/android/widget/VideoView2.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.media.AudioAttributes;
+import android.media.MediaPlayer;
+import android.media.update.ApiLoader;
+import android.media.update.VideoView2Provider;
+import android.media.update.ViewProvider;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
+
+/**
+ * TODO PUBLIC API
+ * @hide
+ */
+public class VideoView2 extends FrameLayout {
+    @IntDef({
+            VIEW_TYPE_TEXTUREVIEW,
+            VIEW_TYPE_SURFACEVIEW
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ViewType {}
+    public static final int VIEW_TYPE_SURFACEVIEW = 1;
+    public static final int VIEW_TYPE_TEXTUREVIEW = 2;
+
+    private final VideoView2Provider mProvider;
+
+    /**
+     * @hide
+     */
+    public VideoView2(@NonNull Context context) {
+        this(context, null);
+    }
+
+    /**
+     * @hide
+     */
+    public VideoView2(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    /**
+     * @hide
+     */
+    public VideoView2(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    /**
+     * @hide
+     */
+    public VideoView2(
+            @NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        mProvider = ApiLoader.getProvider(context).createVideoView2(this, new SuperProvider());
+    }
+
+    /**
+     * @hide
+     */
+    public VideoView2Provider getProvider() {
+        return mProvider;
+    }
+
+    /**
+     * @hide
+     */
+    public void start() {
+        mProvider.start_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void pause() {
+        mProvider.pause_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public int getDuration() {
+        return mProvider.getDuration_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public int getCurrentPosition() {
+        return mProvider.getCurrentPosition_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void seekTo(int msec) {
+        mProvider.seekTo_impl(msec);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isPlaying() {
+        return mProvider.isPlaying_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public int getBufferPercentage() {
+        return mProvider.getBufferPercentage_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public int getAudioSessionId() {
+        return mProvider.getAudioSessionId_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void showSubtitle() {
+        mProvider.showSubtitle_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void hideSubtitle() {
+        mProvider.hideSubtitle_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void setAudioFocusRequest(int focusGain) {
+        mProvider.setAudioFocusRequest_impl(focusGain);
+    }
+
+    /**
+     * @hide
+     */
+    public void setAudioAttributes(@NonNull AudioAttributes attributes) {
+        mProvider.setAudioAttributes_impl(attributes);
+    }
+
+    /**
+     * @hide
+     */
+    public void setVideoPath(String path) {
+        mProvider.setVideoPath_impl(path);
+    }
+
+    /**
+     * @hide
+     */
+    public void setVideoURI(Uri uri) {
+        mProvider.setVideoURI_impl(uri);
+    }
+
+    /**
+     * @hide
+     */
+    public void setVideoURI(Uri uri, Map<String, String> headers) {
+        mProvider.setVideoURI_impl(uri, headers);
+    }
+
+    /**
+     * @hide
+     */
+    public void setMediaController2(MediaController2 controllerView) {
+        mProvider.setMediaController2_impl(controllerView);
+    }
+
+    /**
+     * @hide
+     */
+    public void setViewType(@ViewType int viewType) {
+        mProvider.setViewType_impl(viewType);
+    }
+
+    /**
+     * @hide
+     */
+    @ViewType
+    public int getViewType() {
+        return mProvider.getViewType_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void stopPlayback() {
+        mProvider.stopPlayback_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
+        mProvider.setOnPreparedListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnCompletionListener(MediaPlayer.OnCompletionListener l) {
+        mProvider.setOnCompletionListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnErrorListener(MediaPlayer.OnErrorListener l) {
+        mProvider.setOnErrorListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnInfoListener(MediaPlayer.OnInfoListener l) {
+        mProvider.setOnInfoListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnViewTypeChangedListener(OnViewTypeChangedListener l) {
+        mProvider.setOnViewTypeChangedListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public interface OnViewTypeChangedListener {
+        /**
+         * @hide
+         */
+        void onViewTypeChanged(@ViewType int viewType);
+    }
+
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return mProvider.getAccessibilityClassName_impl();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        return mProvider.onTouchEvent_impl(ev);
+    }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent ev) {
+        return mProvider.onTrackballEvent_impl(ev);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return mProvider.onKeyDown_impl(keyCode, event);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        mProvider.onFinishInflate_impl();
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return mProvider.dispatchKeyEvent_impl(event);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        mProvider.setEnabled_impl(enabled);
+    }
+
+    private class SuperProvider implements ViewProvider {
+        @Override
+        public void onAttachedToWindow_impl() {
+            VideoView2.super.onAttachedToWindow();
+        }
+
+        @Override
+        public void onDetachedFromWindow_impl() {
+            VideoView2.super.onDetachedFromWindow();
+        }
+
+        @Override
+        public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+            VideoView2.super.onLayout(changed, left, top, right, bottom);
+        }
+
+        @Override
+        public void draw_impl(Canvas canvas) {
+            VideoView2.super.draw(canvas);
+        }
+
+        @Override
+        public CharSequence getAccessibilityClassName_impl() {
+            return VideoView2.super.getAccessibilityClassName();
+        }
+
+        @Override
+        public boolean onTouchEvent_impl(MotionEvent ev) {
+            return VideoView2.super.onTouchEvent(ev);
+        }
+
+        @Override
+        public boolean onTrackballEvent_impl(MotionEvent ev) {
+            return VideoView2.super.onTrackballEvent(ev);
+        }
+
+        @Override
+        public boolean onKeyDown_impl(int keyCode, KeyEvent event) {
+            return VideoView2.super.onKeyDown(keyCode, event);
+        }
+
+        @Override
+        public void onFinishInflate_impl() {
+            VideoView2.super.onFinishInflate();
+        }
+
+        @Override
+        public boolean dispatchKeyEvent_impl(KeyEvent event) {
+            return VideoView2.super.dispatchKeyEvent(event);
+        }
+
+        @Override
+        public void setEnabled_impl(boolean enabled) {
+            VideoView2.super.setEnabled(enabled);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
new file mode 100644
index 0000000..042da36
--- /dev/null
+++ b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.app;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.util.Log;
+import com.android.internal.R;
+
+/**
+ * This dialog is shown to the user before an activity in a harmful app is launched.
+ *
+ * See {@code PackageManager.setHarmfulAppInfo} for more info.
+ */
+public class HarmfulAppWarningActivity extends AlertActivity implements
+        DialogInterface.OnClickListener {
+    private static final String TAG = "HarmfulAppWarningActivity";
+
+    private static final String EXTRA_HARMFUL_APP_WARNING = "harmful_app_warning";
+
+    private String mPackageName;
+    private String mHarmfulAppWarning;
+    private IntentSender mTarget;
+
+    // [b/63909431] STOPSHIP replace placeholder UI with final Harmful App Warning UI
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+        mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+        mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+        mHarmfulAppWarning = intent.getStringExtra(EXTRA_HARMFUL_APP_WARNING);
+
+        if (mPackageName == null || mTarget == null || mHarmfulAppWarning == null) {
+            Log.wtf(TAG, "Invalid intent: " + intent.toString());
+            finish();
+        }
+
+        AlertController.AlertParams p = mAlertParams;
+        p.mTitle = getString(R.string.harmful_app_warning_title);
+        p.mMessage = mHarmfulAppWarning;
+        p.mPositiveButtonText = getString(R.string.harmful_app_warning_launch_anyway);
+        p.mPositiveButtonListener = this;
+        p.mNegativeButtonText = getString(R.string.harmful_app_warning_uninstall);
+        p.mNegativeButtonListener = this;
+
+        mAlert.installContent(mAlertParams);
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        switch (which) {
+            case DialogInterface.BUTTON_POSITIVE:
+                getPackageManager().setHarmfulAppWarning(mPackageName, null);
+
+                IntentSender target = getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
+                try {
+                    startIntentSenderForResult(target, -1, null, 0, 0, 0);
+                } catch (IntentSender.SendIntentException e) {
+                    // ignore..
+                }
+                finish();
+                break;
+            case DialogInterface.BUTTON_NEGATIVE:
+                getPackageManager().deletePackage(mPackageName, null, 0);
+                finish();
+                break;
+        }
+    }
+
+    public static Intent createHarmfulAppWarningIntent(Context context, String targetPackageName,
+            IntentSender target, CharSequence harmfulAppWarning) {
+        Intent intent = new Intent();
+        intent.setClass(context, HarmfulAppWarningActivity.class);
+        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
+        intent.putExtra(Intent.EXTRA_INTENT, target);
+        intent.putExtra(EXTRA_HARMFUL_APP_WARNING, harmfulAppWarning);
+        return intent;
+    }
+}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 5d4bccc..388180d 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -123,8 +123,6 @@
     void noteWifiScanStoppedFromSource(in WorkSource ws);
     void noteWifiBatchedScanStartedFromSource(in WorkSource ws, int csph);
     void noteWifiBatchedScanStoppedFromSource(in WorkSource ws);
-    void noteWifiMulticastEnabledFromSource(in WorkSource ws);
-    void noteWifiMulticastDisabledFromSource(in WorkSource ws);
     void noteWifiRadioPowerState(int powerState, long timestampNs, int uid);
     void noteNetworkInterfaceType(String iface, int type);
     void noteNetworkStatsEnabled();
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 2eadaf3..902c8c1 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -111,7 +111,7 @@
     @Override
     public void onClick(DialogInterface dialog, int which) {
         if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE && which == DialogInterface.BUTTON_POSITIVE) {
-            UserManager.get(this).trySetQuietModeEnabled(false, UserHandle.of(mUserId), mTarget);
+            UserManager.get(this).requestQuietModeEnabled(false, UserHandle.of(mUserId), mTarget);
         }
     }
 
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 79f4c1b..a0be64b 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -89,8 +89,8 @@
         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
-        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b8ff9e4..439e5df 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4062,7 +4062,8 @@
 
     public void noteWakupAlarmLocked(String packageName, int uid, WorkSource workSource,
             String tag) {
-
+        final int[] uids = new int[1];
+        final String[] tags = new String[1];
         if (workSource != null) {
             for (int i = 0; i < workSource.size(); ++i) {
                 uid = workSource.get(i);
@@ -4073,8 +4074,9 @@
                             workSourceName != null ? workSourceName : packageName);
                     pkg.noteWakeupAlarmLocked(tag);
                 }
-
-                StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
+                uids[0] = workSource.get(i);
+                tags[0] = workSource.getName(i);
+                StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uids, tags, tag);
             }
 
             ArrayList<WorkChain> workChains = workSource.getWorkChains();
@@ -4087,9 +4089,7 @@
                         BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName);
                         pkg.noteWakeupAlarmLocked(tag);
                     }
-
-                    // TODO(statsd): Log the full attribution chain here once it's available
-                    StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
+                    StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, wc.getUids(), wc.getTags(), tag);
                 }
             }
         } else {
@@ -4097,7 +4097,9 @@
                 BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName);
                 pkg.noteWakeupAlarmLocked(tag);
             }
-            StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
+            uids[0] = uid;
+            tags[0] = null;
+            StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uids, tags, tag);
         }
     }
 
@@ -4221,6 +4223,10 @@
             if (wc != null) {
                 StatsLog.write(
                         StatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(), type, name, 1);
+            } else {
+                final int[] uids = new int[] { uid };
+                final String[] tags = new String[] { null };
+                StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags, type, name, 1);
             }
         }
     }
@@ -4261,6 +4267,10 @@
             if (wc != null) {
                 StatsLog.write(
                         StatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(), type, name, 0);
+            } else {
+                final int[] uids = new int[] { uid };
+                final String[] tags = new String[] { null };
+                StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags, type, name, 0);
             }
         }
     }
@@ -4354,18 +4364,27 @@
     }
 
     public void noteLongPartialWakelockStart(String name, String historyName, int uid) {
+        final int[] uids = new int[] { uid };
+        final String[] tags = new String[] { null };
+        StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
+                uids, tags, name, historyName, 1);
+
         uid = mapUid(uid);
         noteLongPartialWakeLockStartInternal(name, historyName, uid);
-        StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, uid, name, historyName, 1);
     }
 
     public void noteLongPartialWakelockStartFromSource(String name, String historyName,
             WorkSource workSource) {
         final int N = workSource.size();
+        final int[] uids = new int[1];
+        final String[] tags = new String[1];
         for (int i = 0; i < N; ++i) {
             final int uid = mapUid(workSource.get(i));
             noteLongPartialWakeLockStartInternal(name, historyName, uid);
-            StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, uid, name, historyName, 1);
+            uids[0] = workSource.get(i);
+            tags[0] = workSource.getName(i);
+            StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, uids, tags, name,
+                    historyName, 1);
         }
 
         final ArrayList<WorkChain> workChains = workSource.getWorkChains();
@@ -4375,9 +4394,8 @@
                 final int uid = workChain.getAttributionUid();
                 noteLongPartialWakeLockStartInternal(name, historyName, uid);
 
-                // TODO(statsd): the Log WorkChain to statds, and not just the uid.
-                StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, uid, name, historyName,
-                        1);
+                StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
+                        workChain.getUids(), workChain.getTags(), name, historyName, 1);
             }
         }
     }
@@ -4397,18 +4415,27 @@
     }
 
     public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
+        int[] uids = new int[] { uid };
+        String[] tags = new String[] { null };
+        StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
+                uids, tags, name, historyName, 0);
+
         uid = mapUid(uid);
         noteLongPartialWakeLockFinishInternal(name, historyName, uid);
-        StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, uid, name, historyName, 0);
     }
 
     public void noteLongPartialWakelockFinishFromSource(String name, String historyName,
             WorkSource workSource) {
         final int N = workSource.size();
+        final int[] uids = new int[1];
+        final String[] tags = new String[1];
         for (int i = 0; i < N; ++i) {
             final int uid = mapUid(workSource.get(i));
             noteLongPartialWakeLockFinishInternal(name, historyName, uid);
-            StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, uid, name, historyName, 0);
+            uids[0] = workSource.get(i);
+            tags[0] = workSource.getName(i);
+            StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
+                    uids, tags, name, historyName, 0);
         }
 
         final ArrayList<WorkChain> workChains = workSource.getWorkChains();
@@ -4416,12 +4443,9 @@
             for (int i = 0; i < workChains.size(); ++i) {
                 final WorkChain workChain = workChains.get(i);
                 final int uid = workChain.getAttributionUid();
-
                 noteLongPartialWakeLockFinishInternal(name, historyName, uid);
-
-                // TODO(statsd): the Log WorkChain to statds, and not just the uid.
-                StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, uid, name, historyName,
-                        0);
+                StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
+                        workChain.getUids(), workChain.getTags(), name, historyName, 0);
             }
         }
     }
@@ -5388,10 +5412,20 @@
         }
         mBluetoothScanNesting++;
 
-        // TODO(statsd): Log WorkChain here if it's non-null.
-        StatsLog.write(StatsLog.BLE_SCAN_STATE_CHANGED, uid, 1);
-        if (isUnoptimized) {
-            StatsLog.write(StatsLog.BLE_UNOPTIMIZED_SCAN_STATE_CHANGED, uid, 1);
+        if (workChain != null) {
+            StatsLog.write(StatsLog.BLE_SCAN_STATE_CHANGED,
+                    workChain.getUids(), workChain.getTags(), 1);
+            if (isUnoptimized) {
+                StatsLog.write(StatsLog.BLE_UNOPTIMIZED_SCAN_STATE_CHANGED,
+                        workChain.getUids(), workChain.getTags(), 1);
+            }
+        } else {
+            final int[] uids = new int[] {uid};
+            final String[] tags = new String[] {null};
+            StatsLog.write(StatsLog.BLE_SCAN_STATE_CHANGED, uids, tags, 1);
+            if (isUnoptimized) {
+                StatsLog.write(StatsLog.BLE_UNOPTIMIZED_SCAN_STATE_CHANGED, uids, tags, 1);
+            }
         }
 
         getUidStatsLocked(uid).noteBluetoothScanStartedLocked(elapsedRealtime, isUnoptimized);
@@ -5428,10 +5462,20 @@
             mBluetoothScanTimer.stopRunningLocked(elapsedRealtime);
         }
 
-        // TODO(statsd): Log WorkChain here if it's non-null.
-        StatsLog.write(StatsLog.BLE_SCAN_STATE_CHANGED, uid, 0);
-        if (isUnoptimized) {
-            StatsLog.write(StatsLog.BLE_UNOPTIMIZED_SCAN_STATE_CHANGED, uid, 0);
+        if (workChain != null) {
+            StatsLog.write(
+                    StatsLog.BLE_SCAN_STATE_CHANGED, workChain.getUids(), workChain.getTags(), 0);
+            if (isUnoptimized) {
+                StatsLog.write(StatsLog.BLE_UNOPTIMIZED_SCAN_STATE_CHANGED,
+                        workChain.getUids(), workChain.getTags(), 0);
+            }
+        } else {
+            final int[] uids = new int[] { uid };
+            final String[] tags = new String[] {null};
+            StatsLog.write(StatsLog.BLE_SCAN_STATE_CHANGED, uids, tags, 0);
+            if (isUnoptimized) {
+                StatsLog.write(StatsLog.BLE_UNOPTIMIZED_SCAN_STATE_CHANGED, uids, tags, 0);
+            }
         }
 
         getUidStatsLocked(uid).noteBluetoothScanStoppedLocked(elapsedRealtime, isUnoptimized);
@@ -5478,27 +5522,23 @@
                 BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
                 uid.noteResetBluetoothScanLocked(elapsedRealtime);
 
-                StatsLog.write(StatsLog.BLE_SCAN_STATE_CHANGED, uid.getUid(), 0);
-
                 List<WorkChain> allWorkChains = uid.getAllBluetoothWorkChains();
                 if (allWorkChains != null) {
                     for (int j = 0; j < allWorkChains.size(); ++j) {
-                        // TODO(statsd) : Log the entire workchain here.
                         StatsLog.write(StatsLog.BLE_SCAN_STATE_CHANGED,
-                                allWorkChains.get(j).getAttributionUid(), 0);
+                                allWorkChains.get(j).getUids(),
+                                allWorkChains.get(j).getTags(), 0);
                     }
-
                     allWorkChains.clear();
                 }
 
                 List<WorkChain> unoptimizedWorkChains = uid.getUnoptimizedBluetoothWorkChains();
                 if (unoptimizedWorkChains != null) {
                     for (int j = 0; j < unoptimizedWorkChains.size(); ++j) {
-                        // TODO(statsd) : Log the entire workchain here.
                         StatsLog.write(StatsLog.BLE_UNOPTIMIZED_SCAN_STATE_CHANGED,
-                                unoptimizedWorkChains.get(j).getAttributionUid(), 0);
+                                unoptimizedWorkChains.get(j).getUids(),
+                                unoptimizedWorkChains.get(j).getTags(), 0);
                     }
-
                     unoptimizedWorkChains.clear();
                 }
             }
@@ -5507,10 +5547,14 @@
 
     public void noteBluetoothScanResultsFromSourceLocked(WorkSource ws, int numNewResults) {
         final int N = ws.size();
+        final int[] uids = new int[1];
+        final String[] tags = new String[1];
         for (int i = 0; i < N; i++) {
             int uid = mapUid(ws.get(i));
             getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
-            StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, uid, numNewResults);
+            uids[0] = ws.get(i);
+            tags[0] = ws.getName(i);
+            StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, uids, tags, numNewResults);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -5519,8 +5563,8 @@
                 final WorkChain wc = workChains.get(i);
                 int uid = mapUid(wc.getAttributionUid());
                 getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
-                // TODO(statsd): Log the entire WorkChain here.
-                StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, uid, numNewResults);
+                StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED,
+                        wc.getUids(), wc.getTags(), numNewResults);
             }
         }
     }
@@ -5835,10 +5879,14 @@
 
     public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
         int N = ws.size();
+        final int[] uids = new int[1];
+        final String[] tags = new String[1];
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.get(i));
             noteFullWifiLockAcquiredLocked(uid);
-            StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED, uid, 1);
+            uids[0] = ws.get(i);
+            tags[0] = ws.getName(i);
+            StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED, uids, tags, 1);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -5847,22 +5895,22 @@
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
                 noteFullWifiLockAcquiredLocked(uid);
-
-                // TODO(statsd): Log workChain instead of uid here.
-                if (DEBUG) {
-                    Slog.v(TAG, "noteFullWifiLockAcquiredFromSourceLocked: " + workChain);
-                }
-                StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED, uid, 1);
+                StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED,
+                        workChain.getUids(), workChain.getTags(), 1);
             }
         }
     }
 
     public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
         int N = ws.size();
+        final int[] uids = new int[1];
+        final String[] tags = new String[1];
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.get(i));
             noteFullWifiLockReleasedLocked(uid);
-            StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED, uid, 0);
+            uids[0] = ws.get(i);
+            tags[0] = ws.getName(i);
+            StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED, uids, tags, 0);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -5871,22 +5919,22 @@
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
                 noteFullWifiLockReleasedLocked(uid);
-
-                // TODO(statsd): Log workChain instead of uid here.
-                if (DEBUG) {
-                    Slog.v(TAG, "noteFullWifiLockReleasedFromSourceLocked: " + workChain);
-                }
-                StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED, uid, 0);
+                StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED,
+                        workChain.getUids(), workChain.getTags(), 0);
             }
         }
     }
 
     public void noteWifiScanStartedFromSourceLocked(WorkSource ws) {
         int N = ws.size();
+        final int[] uids = new int[1];
+        final String[] tags = new String[1];
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.get(i));
             noteWifiScanStartedLocked(uid);
-            StatsLog.write(StatsLog.WIFI_SCAN_STATE_CHANGED, uid, 1);
+            uids[0] = ws.get(i);
+            tags[0] = ws.getName(i);
+            StatsLog.write(StatsLog.WIFI_SCAN_STATE_CHANGED, uids, tags, 1);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -5895,22 +5943,22 @@
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
                 noteWifiScanStartedLocked(uid);
-
-                // TODO(statsd): Log workChain instead of uid here.
-                if (DEBUG) {
-                    Slog.v(TAG, "noteWifiScanStartedFromSourceLocked: " + workChain);
-                }
-                StatsLog.write(StatsLog.WIFI_SCAN_STATE_CHANGED, uid, 1);
+                StatsLog.write(StatsLog.WIFI_SCAN_STATE_CHANGED, workChain.getUids(),
+                        workChain.getTags(), 1);
             }
         }
     }
 
     public void noteWifiScanStoppedFromSourceLocked(WorkSource ws) {
         int N = ws.size();
+        final int[] uids = new int[1];
+        final String[] tags = new String[1];
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.get(i));
             noteWifiScanStoppedLocked(uid);
-            StatsLog.write(StatsLog.WIFI_SCAN_STATE_CHANGED, uid, 0);
+            uids[0] = ws.get(i);
+            tags[0] = ws.getName(i);
+            StatsLog.write(StatsLog.WIFI_SCAN_STATE_CHANGED, uids, tags, 0);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -5919,11 +5967,8 @@
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
                 noteWifiScanStoppedLocked(uid);
-
-                if (DEBUG) {
-                    Slog.v(TAG, "noteWifiScanStoppedFromSourceLocked: " + workChain);
-                }
-                StatsLog.write(StatsLog.WIFI_SCAN_STATE_CHANGED, uid, 0);
+                StatsLog.write(StatsLog.WIFI_SCAN_STATE_CHANGED,
+                        workChain.getUids(), workChain.getTags(), 0);
             }
         }
     }
@@ -5956,34 +6001,6 @@
         }
     }
 
-    public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
-        int N = ws.size();
-        for (int i=0; i<N; i++) {
-            noteWifiMulticastEnabledLocked(ws.get(i));
-        }
-
-        final List<WorkChain> workChains = ws.getWorkChains();
-        if (workChains != null) {
-            for (int i = 0; i < workChains.size(); ++i) {
-                noteWifiMulticastEnabledLocked(workChains.get(i).getAttributionUid());
-            }
-        }
-    }
-
-    public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
-        int N = ws.size();
-        for (int i=0; i<N; i++) {
-            noteWifiMulticastDisabledLocked(ws.get(i));
-        }
-
-        final List<WorkChain> workChains = ws.getWorkChains();
-        if (workChains != null) {
-            for (int i = 0; i < workChains.size(); ++i) {
-                noteWifiMulticastDisabledLocked(workChains.get(i).getAttributionUid());
-            }
-        }
-    }
-
     private static String[] includeInStringArray(String[] array, String str) {
         if (ArrayUtils.indexOf(array, str) >= 0) {
             return array;
@@ -6917,16 +6934,18 @@
 
         public void noteAudioTurnedOnLocked(long elapsedRealtimeMs) {
             createAudioTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
-            // TODO(statsd): Possibly use a worksource instead of a uid.
-            StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, getUid(), 1);
+            final int[] uids = new int[] { getUid() };
+            final String[] tags = new String[] { null };
+            StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, uids, tags, 1);
         }
 
         public void noteAudioTurnedOffLocked(long elapsedRealtimeMs) {
             if (mAudioTurnedOnTimer != null) {
                 mAudioTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
                 if (!mAudioTurnedOnTimer.isRunningLocked()) { // only tell statsd if truly stopped
-                    // TODO(statsd): Possibly use a worksource instead of a uid.
-                    StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, getUid(), 0);
+                    final int[] uids = new int[] { getUid() };
+                    final String[] tags = new String[] { null };
+                    StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, uids, tags, 0);
                 }
             }
         }
@@ -6934,8 +6953,9 @@
         public void noteResetAudioLocked(long elapsedRealtimeMs) {
             if (mAudioTurnedOnTimer != null) {
                 mAudioTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
-                // TODO(statsd): Possibly use a worksource instead of a uid.
-                StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, getUid(), 0);
+                final int[] uids = new int[] { getUid() };
+                final String[] tags = new String[] { null };
+                StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, uids, tags, 0);
             }
         }
 
@@ -6949,16 +6969,18 @@
 
         public void noteVideoTurnedOnLocked(long elapsedRealtimeMs) {
             createVideoTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
-            // TODO(statsd): Possibly use a worksource instead of a uid.
-            StatsLog.write(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, getUid(), 1);
+            final int[] uids = new int[] { getUid() };
+            final String[] tags = new String[] { null };
+            StatsLog.write(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, uids, tags, 1);
         }
 
         public void noteVideoTurnedOffLocked(long elapsedRealtimeMs) {
             if (mVideoTurnedOnTimer != null) {
                 mVideoTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
                 if (!mVideoTurnedOnTimer.isRunningLocked()) { // only tell statsd if truly stopped
-                    // TODO(statsd): Possibly use a worksource instead of a uid.
-                    StatsLog.write(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, getUid(), 0);
+                    final int[] uids = new int[] { getUid() };
+                    final String[] tags = new String[] { null };
+                    StatsLog.write(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, uids, tags, 0);
                 }
             }
         }
@@ -6966,8 +6988,9 @@
         public void noteResetVideoLocked(long elapsedRealtimeMs) {
             if (mVideoTurnedOnTimer != null) {
                 mVideoTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
-                // TODO(statsd): Possibly use a worksource instead of a uid.
-                StatsLog.write(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, getUid(), 0);
+                final int[] uids = new int[] { getUid() };
+                final String[] tags = new String[] { null };
+                StatsLog.write(StatsLog.MEDIA_CODEC_ACTIVITY_CHANGED, uids, tags, 0);
             }
         }
 
@@ -6981,16 +7004,18 @@
 
         public void noteFlashlightTurnedOnLocked(long elapsedRealtimeMs) {
             createFlashlightTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
-            // TODO(statsd): Possibly use a worksource instead of a uid.
-            StatsLog.write(StatsLog.FLASHLIGHT_STATE_CHANGED, getUid(), 1);
+            final int[] uids = new int[] { getUid() };
+            final String[] tags = new String[] { null };
+            StatsLog.write(StatsLog.FLASHLIGHT_STATE_CHANGED, uids, tags, 1);
         }
 
         public void noteFlashlightTurnedOffLocked(long elapsedRealtimeMs) {
             if (mFlashlightTurnedOnTimer != null) {
                 mFlashlightTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
                 if (!mFlashlightTurnedOnTimer.isRunningLocked()) {
-                    // TODO(statsd): Possibly use a worksource instead of a uid.
-                    StatsLog.write(StatsLog.FLASHLIGHT_STATE_CHANGED, getUid(), 0);
+                    final int[] uids = new int[] { getUid() };
+                    final String[] tags = new String[] { null };
+                    StatsLog.write(StatsLog.FLASHLIGHT_STATE_CHANGED, uids, tags, 0);
                 }
             }
         }
@@ -6998,8 +7023,9 @@
         public void noteResetFlashlightLocked(long elapsedRealtimeMs) {
             if (mFlashlightTurnedOnTimer != null) {
                 mFlashlightTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
-                // TODO(statsd): Possibly use a worksource instead of a uid.
-                StatsLog.write(StatsLog.FLASHLIGHT_STATE_CHANGED, getUid(), 0);
+                final int[] uids = new int[] { getUid() };
+                final String[] tags = new String[] { null };
+                StatsLog.write(StatsLog.FLASHLIGHT_STATE_CHANGED, uids, tags, 0);
             }
         }
 
@@ -7013,16 +7039,18 @@
 
         public void noteCameraTurnedOnLocked(long elapsedRealtimeMs) {
             createCameraTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
-            // TODO(statsd): Possibly use a worksource instead of a uid.
-            StatsLog.write(StatsLog.CAMERA_STATE_CHANGED, getUid(), 1);
+            final int[] uids = new int[] { getUid() };
+            final String[] tags = new String[] { null };
+            StatsLog.write(StatsLog.CAMERA_STATE_CHANGED, uids, tags, 1);
         }
 
         public void noteCameraTurnedOffLocked(long elapsedRealtimeMs) {
             if (mCameraTurnedOnTimer != null) {
                 mCameraTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
                 if (!mCameraTurnedOnTimer.isRunningLocked()) { // only tell statsd if truly stopped
-                    // TODO(statsd): Possibly use a worksource instead of a uid.
-                    StatsLog.write(StatsLog.CAMERA_STATE_CHANGED, getUid(), 0);
+                    final int[] uids = new int[] { getUid() };
+                    final String[] tags = new String[] { null };
+                    StatsLog.write(StatsLog.CAMERA_STATE_CHANGED, uids, tags, 0);
                 }
             }
         }
@@ -7030,8 +7058,9 @@
         public void noteResetCameraLocked(long elapsedRealtimeMs) {
             if (mCameraTurnedOnTimer != null) {
                 mCameraTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
-                // TODO(statsd): Possibly use a worksource instead of a uid.
-                StatsLog.write(StatsLog.CAMERA_STATE_CHANGED, getUid(), 0);
+                final int[] uids = new int[] { getUid() };
+                final String[] tags = new String[] { null };
+                StatsLog.write(StatsLog.CAMERA_STATE_CHANGED, uids, tags, 0);
             }
         }
 
@@ -9593,8 +9622,9 @@
             DualTimer t = mSyncStats.startObject(name);
             if (t != null) {
                 t.startRunningLocked(elapsedRealtimeMs);
-                // TODO(statsd): Possibly use a worksource instead of a uid.
-                StatsLog.write(StatsLog.SYNC_STATE_CHANGED, getUid(), name, 1);
+                final int[] uids = new int[] { getUid() };
+                final String[] tags = new String[] { null };
+                StatsLog.write(StatsLog.SYNC_STATE_CHANGED, uids, tags, name, 1);
             }
         }
 
@@ -9603,8 +9633,9 @@
             if (t != null) {
                 t.stopRunningLocked(elapsedRealtimeMs);
                 if (!t.isRunningLocked()) { // only tell statsd if truly stopped
-                    // TODO(statsd): Possibly use a worksource instead of a uid.
-                    StatsLog.write(StatsLog.SYNC_STATE_CHANGED, getUid(), name, 0);
+                    final int[] uids = new int[] { getUid() };
+                    final String[] tags = new String[] { null };
+                    StatsLog.write(StatsLog.SYNC_STATE_CHANGED, uids, tags, name, 0);
                 }
             }
         }
@@ -9613,8 +9644,9 @@
             DualTimer t = mJobStats.startObject(name);
             if (t != null) {
                 t.startRunningLocked(elapsedRealtimeMs);
-                // TODO(statsd): Possibly use a worksource instead of a uid.
-                StatsLog.write(StatsLog.SCHEDULED_JOB_STATE_CHANGED, getUid(), name, 1);
+                final int[] uids = new int[] { getUid() };
+                final String[] tags = new String[] { null };
+                StatsLog.write(StatsLog.SCHEDULED_JOB_STATE_CHANGED, uids, tags, name, 1);
             }
         }
 
@@ -9623,8 +9655,9 @@
             if (t != null) {
                 t.stopRunningLocked(elapsedRealtimeMs);
                 if (!t.isRunningLocked()) { // only tell statsd if truly stopped
-                    // TODO(statsd): Possibly use a worksource instead of a uid.
-                    StatsLog.write(StatsLog.SCHEDULED_JOB_STATE_CHANGED, getUid(), name, 0);
+                    final int[] uids = new int[] { getUid() };
+                    final String[] tags = new String[] { null };
+                    StatsLog.write(StatsLog.SCHEDULED_JOB_STATE_CHANGED, uids, tags, name, 0);
                 }
             }
             if (mBsi.mOnBatteryTimeBase.isRunning()) {
@@ -9735,11 +9768,12 @@
         public void noteStartSensor(int sensor, long elapsedRealtimeMs) {
             DualTimer t = getSensorTimerLocked(sensor, /* create= */ true);
             t.startRunningLocked(elapsedRealtimeMs);
-            // TODO(statsd): Possibly use a worksource instead of a uid.
+            final int[] uids = new int[] { getUid() };
+            final String[] tags = new String[] { null };
             if (sensor == Sensor.GPS) {
-                StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, getUid(), 1);
+                StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, uids, tags, 1);
             } else {
-                StatsLog.write(StatsLog.SENSOR_STATE_CHANGED, getUid(), sensor, 1);
+                StatsLog.write(StatsLog.SENSOR_STATE_CHANGED, uids, tags, sensor, 1);
             }
         }
 
@@ -9750,10 +9784,12 @@
                 t.stopRunningLocked(elapsedRealtimeMs);
                 if (!t.isRunningLocked()) { // only tell statsd if truly stopped
                     // TODO(statsd): Possibly use a worksource instead of a uid.
+                    final int[] uids = new int[] { getUid() };
+                    final String[] tags = new String[] { null };
                     if (sensor == Sensor.GPS) {
-                        StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, getUid(), 0);
+                        StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, uids, tags, 0);
                     } else {
-                        StatsLog.write(StatsLog.SENSOR_STATE_CHANGED, getUid(), sensor, 0);
+                        StatsLog.write(StatsLog.SENSOR_STATE_CHANGED, uids, tags, sensor, 0);
                     }
                 }
             }
diff --git a/core/java/com/android/internal/os/KernelCpuSpeedReader.java b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
index 4c0370c..98fea01 100644
--- a/core/java/com/android/internal/os/KernelCpuSpeedReader.java
+++ b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
@@ -38,6 +38,7 @@
     private static final String TAG = "KernelCpuSpeedReader";
 
     private final String mProcFile;
+    private final int mNumSpeedSteps;
     private final long[] mLastSpeedTimesMs;
     private final long[] mDeltaSpeedTimesMs;
 
@@ -50,6 +51,7 @@
     public KernelCpuSpeedReader(int cpuNumber, int numSpeedSteps) {
         mProcFile = String.format("/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state",
                 cpuNumber);
+        mNumSpeedSteps = numSpeedSteps;
         mLastSpeedTimesMs = new long[numSpeedSteps];
         mDeltaSpeedTimesMs = new long[numSpeedSteps];
         long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK);
@@ -90,4 +92,31 @@
         }
         return mDeltaSpeedTimesMs;
     }
+
+    /**
+     * @return The time (in milliseconds) spent at different cpu speeds. The values should be
+     * monotonically increasing, unless the cpu was hotplugged.
+     */
+    public long[] readAbsolute() {
+        StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads();
+        long[] speedTimeMs = new long[mNumSpeedSteps];
+        try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) {
+            TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
+            String line;
+            int speedIndex = 0;
+            while (speedIndex < mNumSpeedSteps && (line = reader.readLine()) != null) {
+                splitter.setString(line);
+                splitter.next();
+                long time = Long.parseLong(splitter.next()) * mJiffyMillis;
+                speedTimeMs[speedIndex] = time;
+                speedIndex++;
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read cpu-freq: " + e.getMessage());
+            Arrays.fill(speedTimeMs, 0);
+        } finally {
+            StrictMode.setThreadPolicy(policy);
+        }
+        return speedTimeMs;
+    }
 }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 5fddfba..95bc352 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -101,7 +101,6 @@
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
@@ -194,8 +193,6 @@
 
     // View added at runtime to draw under the status bar area
     private View mStatusGuard;
-    // View added at runtime to draw under the navigation bar area
-    private View mNavigationGuard;
 
     private final ColorViewState mStatusColorViewState =
             new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES);
@@ -1002,7 +999,6 @@
         mFrameOffsets.set(insets.getSystemWindowInsets());
         insets = updateColorViews(insets, true /* animate */);
         insets = updateStatusGuard(insets);
-        insets = updateNavigationGuard(insets);
         if (getForeground() != null) {
             drawableChanged();
         }
@@ -1062,7 +1058,10 @@
         WindowManager.LayoutParams attrs = mWindow.getAttributes();
         int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
 
-        if (!mWindow.mIsFloating) {
+        // IME is an exceptional floating window that requires color view.
+        final boolean isImeWindow =
+                mWindow.getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+        if (!mWindow.mIsFloating || isImeWindow) {
             boolean disallowAnimate = !isLaidOut();
             disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
                     & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
@@ -1363,7 +1362,7 @@
                         if (mStatusGuard == null) {
                             mStatusGuard = new View(mContext);
                             mStatusGuard.setBackgroundColor(mContext.getColor(
-                                    R.color.input_method_navigation_guard));
+                                    R.color.decor_view_status_guard));
                             addView(mStatusGuard, indexOfChild(mStatusColorViewState.view),
                                     new LayoutParams(LayoutParams.MATCH_PARENT,
                                             mlp.topMargin, Gravity.START | Gravity.TOP));
@@ -1407,51 +1406,6 @@
         return insets;
     }
 
-    private WindowInsets updateNavigationGuard(WindowInsets insets) {
-        // IME windows lay out below the nav bar, but the content view must not (for back compat)
-        // Only make this adjustment if the window is not requesting layout in overscan
-        if (mWindow.getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD
-                && (mWindow.getAttributes().flags & FLAG_LAYOUT_IN_OVERSCAN) == 0) {
-            // prevent the content view from including the nav bar height
-            if (mWindow.mContentParent != null) {
-                if (mWindow.mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
-                    MarginLayoutParams mlp =
-                            (MarginLayoutParams) mWindow.mContentParent.getLayoutParams();
-                    mlp.bottomMargin = insets.getSystemWindowInsetBottom();
-                    mWindow.mContentParent.setLayoutParams(mlp);
-                }
-            }
-            // position the navigation guard view, creating it if necessary
-            if (mNavigationGuard == null) {
-                mNavigationGuard = new View(mContext);
-                mNavigationGuard.setBackgroundColor(mContext.getColor(
-                        R.color.input_method_navigation_guard));
-                addView(mNavigationGuard, indexOfChild(mNavigationColorViewState.view),
-                        new LayoutParams(LayoutParams.MATCH_PARENT,
-                                insets.getSystemWindowInsetBottom(),
-                                Gravity.START | Gravity.BOTTOM));
-            } else {
-                LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams();
-                lp.height = insets.getSystemWindowInsetBottom();
-                mNavigationGuard.setLayoutParams(lp);
-            }
-            updateNavigationGuardColor();
-            insets = insets.consumeSystemWindowInsets(
-                    false, false, false, true /* bottom */);
-        }
-        return insets;
-    }
-
-    void updateNavigationGuardColor() {
-        if (mNavigationGuard != null) {
-            // Make navigation bar guard invisible if the transparent color is specified.
-            // Only TRANSPARENT is sufficient for hiding the navigation bar if the no software
-            // keyboard is shown by IMS.
-            mNavigationGuard.setVisibility(mWindow.getNavigationBarColor() == Color.TRANSPARENT ?
-                    View.INVISIBLE : View.VISIBLE);
-        }
-    }
-
     /**
      * Overrides the view outline when the activity enters picture-in-picture to ensure that it has
      * an opaque shadow even if the window background is completely transparent. This only applies
@@ -2103,7 +2057,7 @@
             for (int i = getChildCount() - 1; i >= 0; i--) {
                 View v = getChildAt(i);
                 if (v != mStatusColorViewState.view && v != mNavigationColorViewState.view
-                        && v != mStatusGuard && v != mNavigationGuard) {
+                        && v != mStatusGuard) {
                     removeViewAt(i);
                 }
             }
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 69184c3..e5d5685 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -35,7 +35,7 @@
 
     void addStateMonitorCallback(IKeyguardStateCallback callback);
     void verifyUnlock(IKeyguardExitCallback callback);
-    void dismiss(IKeyguardDismissCallback callback);
+    void dismiss(IKeyguardDismissCallback callback, CharSequence message);
     void onDreamingStarted();
     void onDreamingStopped();
 
diff --git a/core/java/com/android/internal/policy/KeyguardDismissCallback.java b/core/java/com/android/internal/policy/KeyguardDismissCallback.java
new file mode 100644
index 0000000..38337ec
--- /dev/null
+++ b/core/java/com/android/internal/policy/KeyguardDismissCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+import android.os.RemoteException;
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+/**
+ * @hide
+ */
+public class KeyguardDismissCallback extends IKeyguardDismissCallback.Stub {
+
+    @Override
+    public void onDismissError() throws RemoteException {
+        // To be overidden
+    }
+
+    @Override
+    public void onDismissSucceeded() throws RemoteException {
+        // To be overidden
+    }
+
+    @Override
+    public void onDismissCancelled() throws RemoteException {
+        // To be overidden
+    }
+}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index b13560c..e8ee29d 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -3807,7 +3807,6 @@
         mForcedNavigationBarColor = true;
         if (mDecor != null) {
             mDecor.updateColorViews(null, false /* animate */);
-            mDecor.updateNavigationGuardColor();
         }
     }
 
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index aa85668..7b023f4 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -184,6 +184,13 @@
     }
 
     /**
+     * Length of the given collection or 0 if it's null.
+     */
+    public static int size(@Nullable Collection<?> collection) {
+        return collection == null ? 0 : collection.size();
+    }
+
+    /**
      * Checks that value is present as at least one of the elements of the array.
      * @param array the array to check in
      * @param value the value to check for
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 7985e57..2f2c747 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.util;
 
-import static com.android.internal.util.ArrayUtils.isEmpty;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.util.ArraySet;
@@ -173,13 +171,20 @@
     }
 
     /**
-     * Returns the size of the given list, or 0 if the list is null
+     * Returns the size of the given collection, or 0 if null
      */
     public static int size(@Nullable Collection<?> cur) {
         return cur != null ? cur.size() : 0;
     }
 
     /**
+     * Returns whether the given collection {@link Collection#isEmpty is empty} or {@code null}
+     */
+    public static boolean isEmpty(@Nullable Collection<?> cur) {
+        return size(cur) == 0;
+    }
+
+    /**
      * Returns the elements of the given list that are of type {@code c}
      */
     public static @NonNull <T> List<T> filter(@Nullable List<?> list, Class<T> c) {
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
index 59e5a64..379602a 100644
--- a/core/java/com/android/internal/util/ObjectUtils.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -29,6 +29,9 @@
         return a != null ? a : Preconditions.checkNotNull(b);
     }
 
+    /**
+     * Compares two {@link Nullable} objects with {@code null} values considered the smallest
+     */
     public static <T extends Comparable> int compare(@Nullable T a, @Nullable T b) {
         if (a != null) {
             return (b != null) ? a.compareTo(b) : 1;
@@ -36,4 +39,13 @@
             return (b != null) ? -1 : 0;
         }
     }
+
+    /**
+     * @return {@code null} if the given instance is not of the given calss, or the given
+     *         instance otherwise
+     */
+    @Nullable
+    public static <S, T extends S> T castOrNull(@Nullable S instance, @NonNull Class<T> c) {
+        return c.isInstance(instance) ? (T) instance : null;
+    }
 }
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
new file mode 100644
index 0000000..f7ea787
--- /dev/null
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -0,0 +1,128 @@
+package com.android.internal.util;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+public class ScreenshotHelper {
+    private static final String TAG = "ScreenshotHelper";
+
+    private static final String SYSUI_PACKAGE = "com.android.systemui";
+    private static final String SYSUI_SCREENSHOT_SERVICE =
+            "com.android.systemui.screenshot.TakeScreenshotService";
+    private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER =
+            "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver";
+
+    // Time until we give up on the screenshot & show an error instead.
+    private final int SCREENSHOT_TIMEOUT_MS = 10000;
+
+    private final Object mScreenshotLock = new Object();
+    private ServiceConnection mScreenshotConnection = null;
+    private final Context mContext;
+
+    public ScreenshotHelper(Context context) {
+        mContext = context;
+    }
+
+    public void takeScreenshot(final int screenshotType, final boolean hasStatus,
+            final boolean hasNav, Handler handler) {
+        synchronized (mScreenshotLock) {
+            if (mScreenshotConnection != null) {
+                return;
+            }
+            final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE,
+                    SYSUI_SCREENSHOT_SERVICE);
+            final Intent serviceIntent = new Intent();
+
+            final Runnable mScreenshotTimeout = new Runnable() {
+                @Override public void run() {
+                    synchronized (mScreenshotLock) {
+                        if (mScreenshotConnection != null) {
+                            mContext.unbindService(mScreenshotConnection);
+                            mScreenshotConnection = null;
+                            notifyScreenshotError();
+                        }
+                    }
+                }
+            };
+
+            serviceIntent.setComponent(serviceComponent);
+            ServiceConnection conn = new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                    synchronized (mScreenshotLock) {
+                        if (mScreenshotConnection != this) {
+                            return;
+                        }
+                        Messenger messenger = new Messenger(service);
+                        Message msg = Message.obtain(null, screenshotType);
+                        final ServiceConnection myConn = this;
+                        Handler h = new Handler(handler.getLooper()) {
+                            @Override
+                            public void handleMessage(Message msg) {
+                                synchronized (mScreenshotLock) {
+                                    if (mScreenshotConnection == myConn) {
+                                        mContext.unbindService(mScreenshotConnection);
+                                        mScreenshotConnection = null;
+                                        handler.removeCallbacks(mScreenshotTimeout);
+                                    }
+                                }
+                            }
+                        };
+                        msg.replyTo = new Messenger(h);
+                        msg.arg1 = hasStatus ? 1: 0;
+                        msg.arg2 = hasNav ? 1: 0;
+                        try {
+                            messenger.send(msg);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Couldn't take screenshot: " + e);
+                        }
+                    }
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName name) {
+                    synchronized (mScreenshotLock) {
+                        if (mScreenshotConnection != null) {
+                            mContext.unbindService(mScreenshotConnection);
+                            mScreenshotConnection = null;
+                            handler.removeCallbacks(mScreenshotTimeout);
+                            notifyScreenshotError();
+                        }
+                    }
+                }
+            };
+            if (mContext.bindServiceAsUser(serviceIntent, conn,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                    UserHandle.CURRENT)) {
+                mScreenshotConnection = conn;
+                handler.postDelayed(mScreenshotTimeout, SCREENSHOT_TIMEOUT_MS);
+            }
+        }
+    }
+
+    /**
+     * Notifies the screenshot service to show an error.
+     */
+    private void notifyScreenshotError() {
+        // If the service process is killed, then ask it to clean up after itself
+        final ComponentName errorComponent = new ComponentName(SYSUI_PACKAGE,
+                SYSUI_SCREENSHOT_ERROR_RECEIVER);
+        // Broadcast needs to have a valid action.  We'll just pick
+        // a generic one, since the receiver here doesn't care.
+        Intent errorIntent = new Intent(Intent.ACTION_USER_PRESENT);
+        errorIntent.setComponent(errorComponent);
+        errorIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+                Intent.FLAG_RECEIVER_FOREGROUND);
+        mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT);
+    }
+
+}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 4e7df28..31d22e0 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -19,9 +19,9 @@
 import android.app.PendingIntent;
 import android.app.trust.IStrongAuthTracker;
 import android.os.Bundle;
-import android.security.recoverablekeystore.KeyEntryRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryMetadata;
+import android.security.keystore.EntryRecoveryData;
+import android.security.keystore.RecoveryData;
+import android.security.keystore.RecoveryMetadata;
 import com.android.internal.widget.ICheckCredentialProgressCallback;
 import com.android.internal.widget.VerifyCredentialResponse;
 
@@ -60,25 +60,25 @@
             in byte[] token, int requestedQuality, int userId);
     void unlockUserWithToken(long tokenHandle, in byte[] token, int userId);
 
-    // RecoverableKeyStoreLoader methods.
+    // Keystore RecoveryManager methods.
     // {@code ServiceSpecificException} may be thrown to signal an error, which caller can
-    // convert to  {@code RecoverableKeyStoreLoader}.
+    // convert to  {@code RecoveryManagerException}.
     void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList);
-    KeyStoreRecoveryData getRecoveryData(in byte[] account);
+    RecoveryData getRecoveryData(in byte[] account);
     byte[] generateAndStoreKey(String alias);
     void removeKey(String alias);
     void setSnapshotCreatedPendingIntent(in PendingIntent intent);
     Map getRecoverySnapshotVersions();
-    void setServerParameters(long serverParameters);
+    void setServerParams(in byte[] serverParams);
     void setRecoveryStatus(in String packageName, in String[] aliases, int status);
     Map getRecoveryStatus(in String packageName);
     void setRecoverySecretTypes(in int[] secretTypes);
     int[] getRecoverySecretTypes();
     int[] getPendingRecoverySecretTypes();
-    void recoverySecretAvailable(in KeyStoreRecoveryMetadata recoverySecret);
+    void recoverySecretAvailable(in RecoveryMetadata recoverySecret);
     byte[] startRecoverySession(in String sessionId,
             in byte[] verifierPublicKey, in byte[] vaultParams, in byte[] vaultChallenge,
-            in List<KeyStoreRecoveryMetadata> secrets);
+            in List<RecoveryMetadata> secrets);
     Map/*<String, byte[]>*/ recoverKeys(in String sessionId, in byte[] recoveryKeyBlob,
-            in List<KeyEntryRecoveryData> applicationKeys);
+            in List<EntryRecoveryData> applicationKeys);
 }
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 792f921..20f05e6 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -20,17 +20,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
+import android.app.Notification;
 import android.content.Context;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Pools;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -41,7 +36,6 @@
 import android.widget.RemoteViews;
 
 import com.android.internal.R;
-import com.android.internal.util.NotificationColorUtil;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -60,12 +54,12 @@
     private int mLayoutColor;
     private CharSequence mAvatarName = "";
     private Icon mAvatarIcon;
-    private ColorFilter mMessageBackgroundFilter;
     private int mTextColor;
     private List<MessagingMessage> mMessages;
     private ArrayList<MessagingMessage> mAddedMessages = new ArrayList<>();
     private boolean mFirstLayout;
     private boolean mIsHidingAnimated;
+    private boolean mNeedsGeneratedAvatar;
 
     public MessagingGroup(@NonNull Context context) {
         super(context);
@@ -94,27 +88,19 @@
         mAvatarView = findViewById(R.id.message_icon);
     }
 
-    public void setSender(CharSequence sender) {
-        if (sender == null) {
-            mAvatarView.setVisibility(GONE);
-            mSenderName.setVisibility(GONE);
-            setGravity(Gravity.END);
-            mMessageBackgroundFilter = new PorterDuffColorFilter(mLayoutColor,
-                    PorterDuff.Mode.SRC_ATOP);
-            mTextColor = NotificationColorUtil.isColorLight(mLayoutColor) ? getNormalTextColor()
-                    : Color.WHITE;
-        } else {
-            mSenderName.setText(sender);
-            mAvatarView.setVisibility(VISIBLE);
-            mSenderName.setVisibility(VISIBLE);
-            setGravity(Gravity.START);
-            mMessageBackgroundFilter = null;
-            mTextColor = getNormalTextColor();
+    public void setSender(Notification.Person sender) {
+        mSenderName.setText(sender.getName());
+        mNeedsGeneratedAvatar = sender.getIcon() == null;
+        if (!mNeedsGeneratedAvatar) {
+            setAvatar(sender.getIcon());
         }
+        mAvatarView.setVisibility(VISIBLE);
+        mSenderName.setVisibility(VISIBLE);
+        mTextColor = getNormalTextColor();
     }
 
     private int getNormalTextColor() {
-        return mContext.getColor(R.color.notification_primary_text_color_light);
+        return mContext.getColor(R.color.notification_secondary_text_color_light);
     }
 
     public void setAvatar(Icon icon) {
@@ -207,10 +193,6 @@
         return mSenderName.getText();
     }
 
-    public void setSenderVisible(boolean visible) {
-        mSenderName.setVisibility(visible ? VISIBLE : GONE);
-    }
-
     public static void dropCache() {
         sInstancePool = new Pools.SynchronizedPool<>(10);
     }
@@ -317,12 +299,6 @@
                 mMessageContainer.removeView(message);
                 mMessageContainer.addView(message, messageIndex);
             }
-            // Let's make sure the message color is correct
-            Drawable targetDrawable = message.getBackground();
-
-            if (targetDrawable != null) {
-                targetDrawable.mutate().setColorFilter(mMessageBackgroundFilter);
-            }
             message.setTextColor(mTextColor);
         }
         mMessages = group;
@@ -390,4 +366,8 @@
     public MessagingLinearLayout getMessageContainer() {
         return mMessageContainer;
     }
+
+    public boolean needsGeneratedAvatar() {
+        return mNeedsGeneratedAvatar;
+    }
 }
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 2acdc01..834c93a 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -69,7 +69,6 @@
     private List<MessagingMessage> mMessages = new ArrayList<>();
     private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
     private MessagingLinearLayout mMessagingLinearLayout;
-    private View mContractedMessage;
     private boolean mShowHistoricMessages;
     private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
     private TextView mTitleView;
@@ -81,6 +80,7 @@
     private Icon mLargeIcon;
     private boolean mIsOneToOne;
     private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
+    private Notification.Person mUser;
 
     public MessagingLayout(@NonNull Context context) {
         super(context);
@@ -129,6 +129,7 @@
         Parcelable[] histMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
         List<Notification.MessagingStyle.Message> newHistoricMessages
                 = Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
+        setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
         mConversationTitle = null;
         TextView headerText = findViewById(R.id.header_text);
         if (headerText != null) {
@@ -152,7 +153,6 @@
         mMessages = messages;
         mHistoricMessages = historicMessages;
 
-        updateContractedMessage();
         updateHistoricMessageVisibility();
         updateTitleAndNamesDisplay();
     }
@@ -163,12 +163,10 @@
         for (int i = 0; i < mGroups.size(); i++) {
             MessagingGroup group = mGroups.get(i);
             CharSequence senderName = group.getSenderName();
-            if (TextUtils.isEmpty(senderName)) {
+            if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
                 continue;
             }
-            boolean visible = !mIsOneToOne;
-            group.setSenderVisible(visible);
-            if ((visible || mLargeIcon == null) && !uniqueNames.containsKey(senderName)) {
+            if (!uniqueNames.containsKey(senderName)) {
                 char c = senderName.charAt(0);
                 if (uniqueCharacters.containsKey(c)) {
                     // this character was already used, lets make it more unique. We first need to
@@ -192,7 +190,8 @@
             // Let's now set the avatars
             MessagingGroup group = mGroups.get(i);
             CharSequence senderName = group.getSenderName();
-            if (TextUtils.isEmpty(senderName) || (mIsOneToOne && mLargeIcon != null)) {
+            if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)
+                    || (mIsOneToOne && mLargeIcon != null)) {
                 continue;
             }
             String symbol = uniqueNames.get(senderName);
@@ -207,7 +206,7 @@
             // Let's now set the avatars
             MessagingGroup group = mGroups.get(i);
             CharSequence senderName = group.getSenderName();
-            if (TextUtils.isEmpty(senderName)) {
+            if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
                 continue;
             }
             if (mIsOneToOne && mLargeIcon != null) {
@@ -234,7 +233,7 @@
         canvas.drawCircle(radius, radius, radius, mPaint);
         boolean needDarkText  = ColorUtils.calculateLuminance(color) > 0.5f;
         mTextPaint.setColor(needDarkText ? Color.BLACK : Color.WHITE);
-        mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.75f : mAvatarSize * 0.4f);
+        mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.5f : mAvatarSize * 0.3f);
         int yPos = (int) (radius - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)) ;
         canvas.drawText(symbol, radius, yPos, mTextPaint);
         return Icon.createWithBitmap(bitmap);
@@ -270,11 +269,15 @@
         mIsOneToOne = oneToOne;
     }
 
+    public void setUser(Notification.Person user) {
+        mUser = user;
+    }
+
     private void addMessagesToGroups(List<MessagingMessage> historicMessages,
             List<MessagingMessage> messages) {
         // Let's first find our groups!
         List<List<MessagingMessage>> groups = new ArrayList<>();
-        List<CharSequence> senders = new ArrayList<>();
+        List<Notification.Person> senders = new ArrayList<>();
 
         // Lets first find the groups
         findGroups(historicMessages, messages, groups, senders);
@@ -283,7 +286,8 @@
         createGroupViews(groups, senders);
     }
 
-    private void createGroupViews(List<List<MessagingMessage>> groups, List<CharSequence> senders) {
+    private void createGroupViews(List<List<MessagingMessage>> groups,
+            List<Notification.Person> senders) {
         mGroups.clear();
         for (int groupIndex = 0; groupIndex < groups.size(); groupIndex++) {
             List<MessagingMessage> group = groups.get(groupIndex);
@@ -314,8 +318,8 @@
 
     private void findGroups(List<MessagingMessage> historicMessages,
             List<MessagingMessage> messages, List<List<MessagingMessage>> groups,
-            List<CharSequence> senders) {
-        CharSequence currentSender = null;
+            List<Notification.Person> senders) {
+        CharSequence currentSenderKey = null;
         List<MessagingMessage> currentGroup = null;
         int histSize = historicMessages.size();
         for (int i = 0; i < histSize + messages.size(); i++) {
@@ -326,35 +330,23 @@
                 message = messages.get(i - histSize);
             }
             boolean isNewGroup = currentGroup == null;
-            CharSequence sender = message.getMessage().getSender();
-            isNewGroup |= !TextUtils.equals(sender, currentSender);
+            Notification.Person sender = message.getMessage().getSenderPerson();
+            CharSequence key = sender == null ? null
+                    : sender.getKey() == null ? sender.getName() : sender.getKey();
+            isNewGroup |= !TextUtils.equals(key, currentSenderKey);
             if (isNewGroup) {
                 currentGroup = new ArrayList<>();
                 groups.add(currentGroup);
+                if (sender == null) {
+                    sender = mUser;
+                }
                 senders.add(sender);
-                currentSender = sender;
+                currentSenderKey = key;
             }
             currentGroup.add(message);
         }
     }
 
-    private void updateContractedMessage() {
-        for (int i = mMessages.size() - 1; i >= 0; i--) {
-            MessagingMessage m = mMessages.get(i);
-            // Incoming messages have a non-empty sender.
-            if (!TextUtils.isEmpty(m.getMessage().getSender())) {
-                mContractedMessage = m;
-                return;
-            }
-        }
-        if (!mMessages.isEmpty()) {
-            // No incoming messages, fall back to outgoing message
-            mContractedMessage = mMessages.get(mMessages.size() - 1);
-            return;
-        }
-        mContractedMessage = null;
-    }
-
     /**
      * Creates new messages, reusing existing ones if they are available.
      *
@@ -430,10 +422,6 @@
         }
     }
 
-    public View getContractedMessage() {
-        return mContractedMessage;
-    }
-
     public MessagingLinearLayout getMessagingLinearLayout() {
         return mMessagingLinearLayout;
     }
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 7635a72..6f2246a 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -22,9 +22,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -504,7 +502,7 @@
     }
 
     private void onCollapsedChanged(boolean isCollapsed) {
-        notifyViewAccessibilityStateChangedIfNeeded(
+        notifyAccessibilityStateChanged(
                 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
 
         if (mScrollIndicatorDrawable != null) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index b3f66e9..96f3308 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -84,7 +84,7 @@
         "android_view_VelocityTracker.cpp",
         "android_text_AndroidCharacter.cpp",
         "android_text_Hyphenator.cpp",
-        "android_text_MeasuredText.cpp",
+        "android_text_MeasuredParagraph.cpp",
         "android_text_StaticLayout.cpp",
         "android_os_Debug.cpp",
         "android_os_GraphicsEnvironment.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6d7fe05..6569b47 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -178,7 +178,7 @@
 extern int register_android_net_NetworkUtils(JNIEnv* env);
 extern int register_android_text_AndroidCharacter(JNIEnv *env);
 extern int register_android_text_Hyphenator(JNIEnv *env);
-extern int register_android_text_MeasuredText(JNIEnv* env);
+extern int register_android_text_MeasuredParagraph(JNIEnv* env);
 extern int register_android_text_StaticLayout(JNIEnv *env);
 extern int register_android_opengl_classes(JNIEnv *env);
 extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -1342,7 +1342,7 @@
     REG_JNI(register_android_content_XmlBlock),
     REG_JNI(register_android_text_AndroidCharacter),
     REG_JNI(register_android_text_Hyphenator),
-    REG_JNI(register_android_text_MeasuredText),
+    REG_JNI(register_android_text_MeasuredParagraph),
     REG_JNI(register_android_text_StaticLayout),
     REG_JNI(register_android_view_InputDevice),
     REG_JNI(register_android_view_KeyCharacterMap),
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index c237564..a0a4be4 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -46,7 +46,7 @@
 static jmethodID gPoint_constructorMethodID;
 static jmethodID gIncomplete_constructorMethodID;
 static jmethodID gCorrupt_constructorMethodID;
-static jmethodID gCallback_onExceptionMethodID;
+static jmethodID gCallback_onPartialImageMethodID;
 static jmethodID gPostProcess_postProcessMethodID;
 static jmethodID gCanvas_constructorMethodID;
 static jmethodID gCanvas_releaseMethodID;
@@ -67,8 +67,8 @@
         kOpaque      = -1,
     };
 
-    std::unique_ptr<SkAndroidCodec> mCodec;
     NinePatchPeeker mPeeker;
+    std::unique_ptr<SkAndroidCodec> mCodec;
 };
 
 static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream) {
@@ -276,7 +276,7 @@
     SkAndroidCodec::AndroidOptions options;
     options.fSampleSize = sampleSize;
     auto result = codec->getAndroidPixels(decodeInfo, bm.getPixels(), bm.rowBytes(), &options);
-    jobject jexception = env->ExceptionOccurred();
+    jthrowable jexception = env->ExceptionOccurred();
     if (jexception) {
         env->ExceptionClear();
     }
@@ -287,12 +287,14 @@
             break;
         case SkCodec::kIncompleteInput:
             if (jcallback && !jexception) {
-                jexception = env->NewObject(gIncomplete_class, gIncomplete_constructorMethodID);
+                jexception = (jthrowable) env->NewObject(gIncomplete_class,
+                                                         gIncomplete_constructorMethodID);
             }
             break;
         case SkCodec::kErrorInInput:
             if (jcallback && !jexception) {
-                jexception = env->NewObject(gCorrupt_class, gCorrupt_constructorMethodID);
+                jexception = (jthrowable) env->NewObject(gCorrupt_class,
+                                                         gCorrupt_constructorMethodID);
             }
             break;
         default:
@@ -303,9 +305,14 @@
     }
 
     if (jexception) {
-        // FIXME: Do not provide a way for the client to force the method to return null.
-        if (!env->CallBooleanMethod(jcallback, gCallback_onExceptionMethodID, jexception) ||
-            env->ExceptionCheck()) {
+        bool throwException = !env->CallBooleanMethod(jcallback, gCallback_onPartialImageMethodID,
+                                                      jexception);
+        if (env->ExceptionCheck()) {
+            return nullptr;
+        }
+
+        if (throwException) {
+            env->Throw(jexception);
             return nullptr;
         }
     }
@@ -512,7 +519,7 @@
     { "nCreate",        "([BII)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
     { "nCreate",        "(Ljava/io/InputStream;[B)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
     { "nCreate",        "(Ljava/io/FileDescriptor;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
-    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder$OnExceptionListener;Landroid/graphics/PostProcess;IILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
+    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder$OnPartialImageListener;Landroid/graphics/PostProcess;IILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/graphics/Point;",          (void*) ImageDecoder_nGetSampledSize },
     { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
@@ -533,8 +540,8 @@
     gCorrupt_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder$CorruptException"));
     gCorrupt_constructorMethodID = GetMethodIDOrDie(env, gCorrupt_class, "<init>", "()V");
 
-    jclass callback_class = FindClassOrDie(env, "android/graphics/ImageDecoder$OnExceptionListener");
-    gCallback_onExceptionMethodID = GetMethodIDOrDie(env, callback_class, "onException", "(Ljava/io/IOException;)Z");
+    jclass callback_class = FindClassOrDie(env, "android/graphics/ImageDecoder$OnPartialImageListener");
+    gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, callback_class, "onPartialImage", "(Ljava/io/IOException;)Z");
 
     jclass postProcess_class = FindClassOrDie(env, "android/graphics/PostProcess");
     gPostProcess_postProcessMethodID = GetMethodIDOrDie(env, postProcess_class, "postProcess", "(Landroid/graphics/Canvas;II)I");
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 1eeea51..1659168 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -146,8 +146,8 @@
         return nullptr;
     }
     jobject jMap = env->NewObject(gHashMapClazz, gHashMapInit);
-    for (const Vndk &vndk : manifest->vndks()) {
-        std::string key = to_string(vndk.versionRange());
+    for (const auto &vndk : manifest->vendorNdks()) {
+        std::string key = vndk.version();
         env->CallObjectMethod(jMap, gHashMapPut,
                 env->NewStringUTF(key.c_str()), toJavaStringArray(env, vndk.libraries()));
     }
diff --git a/core/jni/android_text_MeasuredText.cpp b/core/jni/android_text_MeasuredParagraph.cpp
similarity index 83%
rename from core/jni/android_text_MeasuredText.cpp
rename to core/jni/android_text_MeasuredParagraph.cpp
index af9d131..bdae0b2 100644
--- a/core/jni/android_text_MeasuredText.cpp
+++ b/core/jni/android_text_MeasuredParagraph.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "MeasuredText"
+#define LOG_TAG "MeasuredParagraph"
 
 #include "ScopedIcuLocale.h"
 #include "unicode/locid.h"
@@ -49,7 +49,7 @@
     return reinterpret_cast<Paint*>(ptr);
 }
 
-static inline minikin::MeasuredText* toMeasuredText(jlong ptr) {
+static inline minikin::MeasuredText* toMeasuredParagraph(jlong ptr) {
     return reinterpret_cast<minikin::MeasuredText*>(ptr);
 }
 
@@ -57,8 +57,8 @@
     return reinterpret_cast<jlong>(ptr);
 }
 
-static void releaseMeasuredText(jlong measuredTextPtr) {
-    delete toMeasuredText(measuredTextPtr);
+static void releaseMeasuredParagraph(jlong measuredTextPtr) {
+    delete toMeasuredParagraph(measuredTextPtr);
 }
 
 // Regular JNI
@@ -84,7 +84,7 @@
 }
 
 // Regular JNI
-static jlong nBuildNativeMeasuredText(JNIEnv* env, jclass /* unused */, jlong builderPtr,
+static jlong nBuildNativeMeasuredParagraph(JNIEnv* env, jclass /* unused */, jlong builderPtr,
                                       jcharArray javaText) {
     ScopedCharArrayRO text(env, javaText);
     const minikin::U16StringPiece textBuffer(text.get(), text.size());
@@ -100,23 +100,23 @@
 
 // CriticalNative
 static jlong nGetReleaseFunc() {
-    return toJLong(&releaseMeasuredText);
+    return toJLong(&releaseMeasuredParagraph);
 }
 
 static const JNINativeMethod gMethods[] = {
-    // MeasuredTextBuilder native functions.
+    // MeasuredParagraphBuilder native functions.
     {"nInitBuilder", "()J", (void*) nInitBuilder},
     {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
     {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
-    {"nBuildNativeMeasuredText", "(J[C)J", (void*) nBuildNativeMeasuredText},
+    {"nBuildNativeMeasuredParagraph", "(J[C)J", (void*) nBuildNativeMeasuredParagraph},
     {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
 
-    // MeasuredText native functions.
+    // MeasuredParagraph native functions.
     {"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc},  // Critical Natives
 };
 
-int register_android_text_MeasuredText(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, "android/text/MeasuredText", gMethods, NELEM(gMethods));
+int register_android_text_MeasuredParagraph(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, "android/text/MeasuredParagraph", gMethods, NELEM(gMethods));
 }
 
 }
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index b5c23df..682dc873 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -174,7 +174,7 @@
 
         // Inputs
         "[C"  // text
-        "J"  // MeasuredText ptr.
+        "J"  // MeasuredParagraph ptr.
         "I"  // length
         "F"  // firstWidth
         "I"  // firstWidthLineCount
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 5e5d59b..0ef5445 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -72,7 +72,6 @@
 
 // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
 void DeleteScreenshot(void* addr, void* context) {
-    SkASSERT(addr == ((ScreenshotClient*) context)->getPixels());
     delete ((ScreenshotClient*) context);
 }
 
diff --git a/core/proto/android/app/statusbarmanager.proto b/core/proto/android/app/statusbarmanager.proto
new file mode 100644
index 0000000..3d1447a
--- /dev/null
+++ b/core/proto/android/app/statusbarmanager.proto
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.app;
+option java_multiple_files = true;
+
+message StatusBarManagerProto {
+  enum WindowState {
+    WINDOW_STATE_SHOWING = 0;
+    WINDOW_STATE_HIDING = 1;
+    WINDOW_STATE_HIDDEN = 2;
+  }
+  enum TransientWindowState {
+    TRANSIENT_BAR_NONE = 0;
+    TRANSIENT_BAR_SHOW_REQUESTED = 1;
+    TRANSIENT_BAR_SHOWING = 2;
+    TRANSIENT_BAR_HIDING = 3;
+  }
+}
diff --git a/core/proto/android/content/activityinfo.proto b/core/proto/android/content/activityinfo.proto
new file mode 100644
index 0000000..012752a
--- /dev/null
+++ b/core/proto/android/content/activityinfo.proto
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.content;
+option java_multiple_files = true;
+
+message ActivityInfoProto {
+  enum ScreenOrientation {
+    SCREEN_ORIENTATION_UNSET = -2;
+    SCREEN_ORIENTATION_UNSPECIFIED = -1;
+    SCREEN_ORIENTATION_LANDSCAPE = 0;
+    SCREEN_ORIENTATION_PORTRAIT = 1;
+    SCREEN_ORIENTATION_USER = 2;
+    SCREEN_ORIENTATION_BEHIND = 3;
+    SCREEN_ORIENTATION_SENSOR = 4;
+    SCREEN_ORIENTATION_NOSENSOR = 5;
+    SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6;
+    SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7;
+    SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;
+    SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;
+    SCREEN_ORIENTATION_FULL_SENSOR = 10;
+    SCREEN_ORIENTATION_USER_LANDSCAPE = 11;
+    SCREEN_ORIENTATION_USER_PORTRAIT = 12;
+    SCREEN_ORIENTATION_FULL_USER = 13;
+    SCREEN_ORIENTATION_LOCKED = 14;
+  }
+}
+
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 9999b4e..331f80f 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -674,14 +674,13 @@
     // needed:
     // top > foreground service > foreground > background > top sleeping > heavy weight > cache
     enum State {
-      // Time this uid has any processes in the top state (or above such as
-      // persistent).
+      // Time this uid has any processes in the top state.
       PROCESS_STATE_TOP = 0;
-      // Time this uid has any process with a started out bound foreground
-      // service, but none in the "top" state.
+      // Time this uid has any process with a started foreground service, but
+      // none in the "top" state.
       PROCESS_STATE_FOREGROUND_SERVICE = 1;
-      // Time this uid has any process in an active foreground state, but none
-      // in the "top sleeping" or better state.
+      // Time this uid has any process in an active foreground state, but none in the
+      // "foreground service" or better state. Persistent and other foreground states go here.
       PROCESS_STATE_FOREGROUND = 2;
       // Time this uid has any process in an active background state, but none
       // in the "foreground" or better state.
diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index 59582ec..07b9ad0 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -228,8 +228,9 @@
     }
     optional PmDexopt pm_dexopt = 20;
 
+    // Read only properites on the device.
     message Ro {
-        optional int32  adb_secure = 1;
+        optional bool  adb_secure = 1;
         optional string arch = 2;
         optional bool   audio_ignore_effects = 3;
         optional bool   audio_monitorRotation = 4;
@@ -262,21 +263,29 @@
         }
         optional Boot boot = 7;
 
+        // boot.img's properties.
         message BootImage {
+            // When the boot.img is built.
             optional string build_date = 1;
-            optional int32  build_date_utc = 2;
+            // UTC timestamp of build date.
+            optional int64 build_date_utc = 2;
+            // Android Build fingerprint of the build, e.g.
+            // google/marlin/marlin:P/MASTER/android-build/dev-keys
             optional string build_fingerprint = 3;
 
             // Next Tag: 4
         }
         optional BootImage bootimage = 8;
 
+        // Version of bootloader on device.
         optional string bootloader = 9;
+        // Kernel bootmode, e.g. charger.
         optional string bootmode = 10;
 
+        // Android Platform build metadata.
         message Build {
             optional string date = 1;
-            optional int32  date_utc = 2;
+            optional int64  date_utc = 2;
             optional string description = 3;
             optional string display_id = 4;
             optional string host = 5;
@@ -304,7 +313,7 @@
         }
         optional Build build = 11;
 
-        optional int32  camera_notify_nfc = 12;
+        optional bool   camera_notify_nfc = 12;
         optional string carrier = 13;
         optional bool   com_android_dataroaming = 14;
         optional bool   com_android_prov_mobiledata = 15;
@@ -327,7 +336,7 @@
         optional string crypto_state = 21;
         optional string crypto_type = 22;
         optional string dalvik_vm_native_bridge = 23;
-        optional bool  debuggable = 24;
+        optional bool   debuggable = 24;
         optional string frp_pst = 25;
         optional string gfx_driver_0 = 26;
 
@@ -426,7 +435,7 @@
 
         message Vendor {
             optional string build_date = 1;
-            optional int32  build_date_utc = 2;
+            optional int64  build_date_utc = 2;
             optional string build_fingerprint = 3;
         }
         optional Vendor vendor = 41;
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index f5d098c..d4bdb9b 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -388,8 +388,9 @@
     optional SettingProto enable_deletion_helper_no_threshold_toggle = 340;
     optional SettingProto notification_snooze_options = 341;
     optional SettingProto enable_gnss_raw_meas_full_tracking = 346;
+    optional SettingProto zram_enabled = 347;
 
-    // Next tag = 347;
+    // Next tag = 348;
 }
 
 message SecureSettingsProto {
diff --git a/core/proto/android/server/appwindowthumbnail.proto b/core/proto/android/server/appwindowthumbnail.proto
new file mode 100644
index 0000000..e67b854
--- /dev/null
+++ b/core/proto/android/server/appwindowthumbnail.proto
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/server/surfaceanimator.proto";
+
+package com.android.server.wm.proto;
+option java_multiple_files = true;
+
+/**
+ * Represents a {@link com.android.server.wm.AppWindowThumbnail} object.
+ */
+message AppWindowThumbnailProto {
+  optional int32 width = 1;
+  optional int32 height = 2;
+  optional SurfaceAnimatorProto surface_animator = 3;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/surfaceanimator.proto b/core/proto/android/server/surfaceanimator.proto
new file mode 100644
index 0000000..60713d7
--- /dev/null
+++ b/core/proto/android/server/surfaceanimator.proto
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/view/surfacecontrol.proto";
+
+package com.android.server.wm.proto;
+option java_multiple_files = true;
+
+/**
+ * Represents a {@link com.android.server.wm.SurfaceAnimator} object.
+ */
+message SurfaceAnimatorProto {
+  optional string animation_adapter = 1;
+  optional .android.view.SurfaceControlProto leash = 2;
+  optional bool animation_start_delayed = 3;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 12aca78..71f33c7 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -16,10 +16,15 @@
 
 syntax = "proto2";
 
+import "frameworks/base/core/proto/android/app/statusbarmanager.proto";
+import "frameworks/base/core/proto/android/content/activityinfo.proto";
 import "frameworks/base/core/proto/android/content/configuration.proto";
 import "frameworks/base/core/proto/android/graphics/rect.proto";
+import "frameworks/base/core/proto/android/server/appwindowthumbnail.proto";
+import "frameworks/base/core/proto/android/server/surfaceanimator.proto";
 import "frameworks/base/core/proto/android/view/displaycutout.proto";
 import "frameworks/base/core/proto/android/view/displayinfo.proto";
+import "frameworks/base/core/proto/android/view/surface.proto";
 import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
 
 package com.android.server.wm.proto;
@@ -47,8 +52,62 @@
   repeated IdentifierProto windows = 3;
 }
 
+message BarControllerProto {
+  optional .android.app.StatusBarManagerProto.WindowState state = 1;
+  optional .android.app.StatusBarManagerProto.TransientWindowState transient_state = 2;
+}
+
+message WindowOrientationListenerProto {
+  optional bool enabled = 1;
+  optional .android.view.SurfaceProto.Rotation rotation = 2;
+}
+
+message KeyguardServiceDelegateProto {
+  optional bool showing = 1;
+  optional bool occluded = 2;
+  optional bool secure = 3;
+  enum ScreenState {
+    SCREEN_STATE_OFF = 0;
+    SCREEN_STATE_TURNING_ON = 1;
+    SCREEN_STATE_ON = 2;
+    SCREEN_STATE_TURNING_OFF = 3;
+  }
+  optional ScreenState screen_state = 4;
+  enum InteractiveState {
+    INTERACTIVE_STATE_SLEEP = 0;
+    INTERACTIVE_STATE_WAKING = 1;
+    INTERACTIVE_STATE_AWAKE = 2;
+    INTERACTIVE_STATE_GOING_TO_SLEEP = 3;
+  }
+  optional InteractiveState interactive_state = 5;
+}
+
 /* represents PhoneWindowManager */
 message WindowManagerPolicyProto {
+  optional int32 last_system_ui_flags = 1;
+  enum UserRotationMode {
+    USER_ROTATION_FREE = 0;
+    USER_ROTATION_LOCKED = 1;
+  }
+  optional UserRotationMode rotation_mode = 2;
+  optional .android.view.SurfaceProto.Rotation rotation = 3;
+  optional .android.content.ActivityInfoProto.ScreenOrientation orientation = 4;
+  optional bool screen_on_fully = 5;
+  optional bool keyguard_draw_complete = 6;
+  optional bool window_manager_draw_complete = 7;
+  optional string focused_app_token = 8;
+  optional IdentifierProto focused_window = 9;
+  optional IdentifierProto top_fullscreen_opaque_window = 10;
+  optional IdentifierProto top_fullscreen_opaque_or_dimming_window = 11;
+  optional bool keyguard_occluded = 12;
+  optional bool keyguard_occluded_changed = 13;
+  optional bool keyguard_occluded_pending = 14;
+  optional bool force_status_bar = 15;
+  optional bool force_status_bar_from_keyguard = 16;
+  optional BarControllerProto status_bar = 17;
+  optional BarControllerProto navigation_bar = 18;
+  optional WindowOrientationListenerProto orientation_listener = 19;
+  optional KeyguardServiceDelegateProto keyguard_delegate = 20;
 }
 
 /* represents AppTransition */
@@ -128,6 +187,12 @@
   optional bool fills_parent = 4;
   optional .android.graphics.RectProto bounds = 5;
   optional bool animation_background_surface_is_dimming = 6;
+  optional bool defer_removal = 7;
+  optional float minimize_amount = 8;
+  optional bool adjusted_for_ime = 9;
+  optional float adjust_ime_amount = 10;
+  optional float adjust_divider_amount = 11;
+  optional .android.graphics.RectProto adjusted_bounds = 12;
 }
 
 /* represents Task */
@@ -138,6 +203,7 @@
   optional bool fills_parent = 4;
   optional .android.graphics.RectProto bounds = 5;
   optional .android.graphics.RectProto temp_inset_bounds = 6;
+  optional bool defer_removal = 7;
 }
 
 /* represents AppWindowToken */
@@ -145,6 +211,27 @@
   /* obtained from ActivityRecord */
   optional string name = 1;
   optional WindowTokenProto window_token = 2;
+  optional bool last_surface_showing = 3;
+  optional bool is_waiting_for_transition_start =  4;
+  optional bool is_really_animating = 5;
+  optional AppWindowThumbnailProto thumbnail = 6;
+  optional bool fills_parent = 7;
+  optional bool app_stopped = 8;
+  optional bool hidden_requested = 9;
+  optional bool client_hidden = 10;
+  optional bool defer_hiding_client = 11;
+  optional bool reported_drawn = 12;
+  optional bool reported_visible = 13;
+  optional int32 num_interesting_windows = 14;
+  optional int32 num_drawn_windows = 15;
+  optional bool all_drawn = 16;
+  optional bool last_all_drawn = 17;
+  optional bool removed = 18;
+  optional IdentifierProto starting_window = 19;
+  optional bool starting_displayed = 20;
+  optional bool starting_moved = 21;
+  optional bool hidden_set_from_transferred_starting_window = 22;
+  repeated .android.graphics.RectProto frozen_bounds = 23;
 }
 
 /* represents WindowToken */
@@ -152,6 +239,9 @@
   optional WindowContainerProto window_container = 1;
   optional int32 hash_code = 2;
   repeated WindowStateProto windows = 3;
+  optional bool hidden = 4;
+  optional bool waiting_to_show = 5;
+  optional bool paused = 6;
 }
 
 /* represents WindowState */
@@ -234,6 +324,7 @@
   optional ConfigurationContainerProto configuration_container = 1;
   optional int32 orientation = 2;
   optional bool visible = 3;
+  optional SurfaceAnimatorProto surface_animator = 4;
 }
 
 /* represents ConfigurationContainer */
diff --git a/core/proto/android/server/windowmanagertrace.proto b/core/proto/android/server/windowmanagertrace.proto
index 0c65bb2..d96953e 100644
--- a/core/proto/android/server/windowmanagertrace.proto
+++ b/core/proto/android/server/windowmanagertrace.proto
@@ -16,11 +16,7 @@
 
 syntax = "proto2";
 
-import "frameworks/base/core/proto/android/content/configuration.proto";
-import "frameworks/base/core/proto/android/graphics/rect.proto";
 import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
-import "frameworks/base/core/proto/android/view/displayinfo.proto";
-import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
 
 package com.android.server.wm.proto;
 
diff --git a/core/proto/android/util/log.proto b/core/proto/android/util/log.proto
index 30ff412..fd4fa9e 100644
--- a/core/proto/android/util/log.proto
+++ b/core/proto/android/util/log.proto
@@ -57,10 +57,10 @@
     optional uint32 tag_index = 6;
 
     message Elem {
-        // must be sync with liblog log/log.h
+        // must be sync with AOSP liblog's log.h
         enum Type {
-            EVENT_TYPE_LIST_STOP = 10; // '\n'
-            EVENT_TYPE_UNKNOWN = 63; // '?'
+            EVENT_TYPE_LIST_STOP = 10; // ascii decimal value of char '\n'
+            EVENT_TYPE_UNKNOWN = 63; // ascii decimal value of char '?'
 
             EVENT_TYPE_INT = 0;
             EVENT_TYPE_LONG = 1;
diff --git a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl b/core/proto/android/view/surface.proto
similarity index 67%
copy from core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl
copy to core/proto/android/view/surface.proto
index fe13179..8f5f695 100644
--- a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl
+++ b/core/proto/android/view/surface.proto
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,15 @@
  * limitations under the License.
  */
 
-package android.security.recoverablekeystore;
+syntax = "proto2";
+package android.view;
+option java_multiple_files = true;
 
-/* @hide */
-parcelable KeyDerivationParameters;
+message SurfaceProto {
+  enum Rotation {
+    ROTATION_0 = 0;
+    ROTATION_90 = 1;
+    ROTATION_180 = 2;
+    ROTATION_270 = 3;
+  }
+}
diff --git a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl b/core/proto/android/view/surfacecontrol.proto
similarity index 65%
copy from core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl
copy to core/proto/android/view/surfacecontrol.proto
index fe13179..9288b4f 100644
--- a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl
+++ b/core/proto/android/view/surfacecontrol.proto
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,15 @@
  * limitations under the License.
  */
 
-package android.security.recoverablekeystore;
+syntax = "proto2";
+package android.view;
 
-/* @hide */
-parcelable KeyDerivationParameters;
+option java_multiple_files = true;
+
+/**
+ * Represents a {@link android.view.SurfaceControl} object.
+ */
+message SurfaceControlProto {
+  optional int32 hash_code = 1;
+  optional string name = 2;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b8d2606..a3e8f1e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -572,6 +572,11 @@
     <protected-broadcast android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
     <protected-broadcast android:name="android.telephony.euicc.action.OTA_STATUS_CHANGED" />
 
+    <!-- Added in P -->
+    <protected-broadcast android:name="android.app.action.PROFILE_OWNER_CHANGED" />
+    <protected-broadcast android:name="android.app.action.TRANSFER_OWNERSHIP_COMPLETE" />
+    <protected-broadcast android:name="android.app.action.DATA_SHARING_RESTRICTION_CHANGED" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -2849,6 +2854,16 @@
         android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
         android:protectionLevel="signature" />
 
+    <!-- @hide
+         Allows an application to change the status of Scoped Access Directory requests granted or
+         rejected by the user.
+         <p>This permission should <em>only</em> be requested by the platform
+         settings app.  This permission cannot be granted to third-party apps.
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to delete cache files.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
@@ -2938,13 +2953,14 @@
 
     <!-- Allows an application to collect usage infomation about brightness slider changes.
          <p>Not for use by third-party applications.</p>
-         TODO: make a System API
-         @hide -->
+         @hide
+         @SystemApi -->
     <permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- Allows an application to modify the display brightness configuration
-         @hide -->
+         @hide
+         @SystemApi -->
     <permission android:name="android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"
         android:protectionLevel="signature|privileged|development" />
 
@@ -3294,6 +3310,10 @@
     <permission android:name="android.permission.BIND_PACKAGE_VERIFIER"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
+    <permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
+        android:protectionLevel="signature|verifier" />
+
     <!-- @SystemApi @hide Intent filter verifier needs to have this permission before the
          PackageManager will trust it to verify intent filters.
     -->
@@ -3380,6 +3400,12 @@
     <permission android:name="android.permission.PROVIDE_TRUST_AGENT"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to show a message
+         on the keyguard when asking to dismiss it.
+         @hide For security reasons, this is a platform-only permission. -->
+    <permission android:name="android.permission.SHOW_KEYGUARD_MESSAGE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to launch the trust agent settings activity.
         @hide -->
     <permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
@@ -3859,6 +3885,13 @@
                   android:excludeFromRecents="true">
         </activity>
 
+        <activity android:name="com.android.internal.app.HarmfulAppWarningActivity"
+                  android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:excludeFromRecents="true"
+                  android:process=":ui"
+                  android:exported="false">
+        </activity>
+
         <receiver android:name="com.android.server.BootReceiver"
                 android:systemUserOnly="true">
             <intent-filter android:priority="1000">
diff --git a/core/res/res/drawable/ic_screenshot.xml b/core/res/res/drawable/ic_screenshot.xml
new file mode 100644
index 0000000..3074b28
--- /dev/null
+++ b/core/res/res/drawable/ic_screenshot.xml
@@ -0,0 +1,33 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24.0dp"
+    android:height="24.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:pathData="M0,0h24v24H0V0z"
+        android:fillColor="#00000000"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M17.0,1.0L7.0,1.0C5.9,1.0 5.0,1.9 5.0,3.0l0.0,18.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L19.0,3.0C19.0,1.9 18.1,1.0 17.0,1.0zM17.0,20.0L7.0,20.0L7.0,4.0l10.0,0.0L17.0,20.0z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M13.0,6.0l-4.0,0.0 0.0,4.0 1.5,0.0 0.0,-2.5 2.5,0.0z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M11.0,18.0l4.0,0.0 0.0,-4.0 -1.5,0.0 0.0,2.5 -2.5,0.0z"/>
+</vector>
diff --git a/core/res/res/drawable/messaging_message_background.xml b/core/res/res/drawable/messaging_message_background.xml
deleted file mode 100644
index 8a2096a..0000000
--- a/core/res/res/drawable/messaging_message_background.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle"
-    android:tint="#14000000">
-    <corners android:radius="4dp" />
-    <padding android:bottom="6dp"
-        android:left="8dp"
-        android:right="8dp"
-        android:top="6dp" />
-</shape>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 3a28f4d..20bdf3f 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -41,6 +41,24 @@
         android:singleLine="true"
         />
     <TextView
+        android:id="@+id/header_text_secondary_divider"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?attr/notificationHeaderTextAppearance"
+        android:layout_marginStart="@dimen/notification_header_separating_margin"
+        android:layout_marginEnd="@dimen/notification_header_separating_margin"
+        android:text="@string/notification_header_divider_symbol"
+        android:visibility="gone"/>
+    <TextView
+        android:id="@+id/header_text_secondary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?attr/notificationHeaderTextAppearance"
+        android:layout_marginStart="@dimen/notification_header_separating_margin"
+        android:layout_marginEnd="@dimen/notification_header_separating_margin"
+        android:visibility="gone"
+        android:singleLine="true"/>
+    <TextView
         android:id="@+id/header_text_divider"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index f72230b..a72ad53 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -21,10 +21,7 @@
     android:layout_height="wrap_content"
     android:tag="messaging"
     >
-    <include layout="@layout/notification_template_header"
-             android:layout_width="wrap_content"
-             android:layout_height="@dimen/notification_header_height"
-             android:layout_marginEnd="56dp"/>
+    <include layout="@layout/notification_template_header"/>
     <LinearLayout
             android:id="@+id/notification_action_list_margin_target"
             android:layout_width="match_parent"
@@ -39,28 +36,19 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="top"
-            android:paddingStart="@dimen/notification_content_margin_start"
-            android:paddingEnd="@dimen/notification_content_margin_end"
+            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
             android:minHeight="@dimen/notification_min_content_height"
             android:layout_marginBottom="@dimen/notification_content_margin_bottom"
             android:orientation="vertical"
             >
-            <include layout="@layout/notification_template_part_line1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-
             <com.android.internal.widget.MessagingLinearLayout
                 android:id="@+id/notification_messaging"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginTop="8dp"
                 android:spacing="@dimen/notification_messaging_spacing" />
         </LinearLayout>
     </LinearLayout>
     <include layout="@layout/notification_material_action_list" />
-    <include layout="@layout/notification_template_right_icon"
-             android:layout_width="wrap_content"
-             android:layout_height="wrap_content"
-             android:layout_marginTop="18dp"
-             android:layout_gravity="top|end"/>
+    <include layout="@layout/notification_template_right_icon"/>
 </com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
index 8973ceb..4ac308a 100644
--- a/core/res/res/layout/notification_template_messaging_group.xml
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -24,7 +24,7 @@
         android:id="@+id/message_icon"
         android:layout_width="@dimen/messaging_avatar_size"
         android:layout_height="@dimen/messaging_avatar_size"
-        android:layout_marginEnd="8dp"
+        android:layout_marginEnd="12dp"
         android:scaleType="centerCrop"
         android:importantForAccessibility="no" />
     <com.android.internal.widget.RemeasuringLinearLayout
@@ -32,19 +32,16 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="vertical">
+        <com.android.internal.widget.ImageFloatingTextView
+            android:id="@+id/message_name"
+            style="@style/Widget.Material.Notification.MessagingName"
+            android:layout_width="wrap_content"
+        />
         <com.android.internal.widget.MessagingLinearLayout
             android:id="@+id/group_message_container"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:spacing="2dp"
             android:layout_weight="1"/>
-        <com.android.internal.widget.ImageFloatingTextView
-            android:id="@+id/message_name"
-            style="@style/Widget.Material.Notification.MessagingName"
-            android:layout_width="wrap_content"
-            android:paddingStart="8dp"
-            android:paddingEnd="8dp"
-            android:paddingTop="2dp"
-        />
     </com.android.internal.widget.RemeasuringLinearLayout>
 </com.android.internal.widget.MessagingGroup>
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index 8fb2887..0b97e45 100644
--- a/core/res/res/layout/notification_template_right_icon.xml
+++ b/core/res/res/layout/notification_template_right_icon.xml
@@ -19,7 +19,7 @@
              android:id="@+id/right_icon_container"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
-             android:layout_marginTop="36dp"
+             android:layout_marginTop="@dimen/notification_content_margin_top"
              android:layout_gravity="top|end">
     <ImageView android:id="@+id/right_icon"
                android:layout_width="@dimen/notification_right_icon_size"
@@ -32,8 +32,8 @@
                android:layout_width="16dp"
                android:layout_height="16dp"
                android:layout_gravity="top|end"
-               android:layout_marginTop="28dp"
-               android:layout_marginEnd="12dp"
+               android:layout_marginTop="27dp"
+               android:layout_marginEnd="16dp"
                android:background="@drawable/notification_reply_background"
                android:src="@drawable/ic_reply_notification"
                android:scaleType="center"
diff --git a/core/res/res/raw/color_fade_frag.frag b/core/res/res/raw/color_fade_frag.frag
index a66a5a7..29975d5 100644
--- a/core/res/res/raw/color_fade_frag.frag
+++ b/core/res/res/raw/color_fade_frag.frag
@@ -3,40 +3,12 @@
 precision mediump float;
 uniform samplerExternalOES texUnit;
 uniform float opacity;
-uniform float saturation;
 uniform float gamma;
 varying vec2 UV;
 
-vec3 rgb2hsl(vec3 rgb)
-{
-    float e = 1.0e-7;
-
-    vec4 p = rgb.g < rgb.b ? vec4(rgb.bg, -1.0, 2.0 / 3.0) : vec4(rgb.gb, 0.0, -1.0 / 3.0);
-    vec4 q = rgb.r < p.x ? vec4(p.xyw, rgb.r) : vec4(rgb.r, p.yzx);
-
-    float v = q.x;
-    float c = v - min(q.w, q.y);
-    float h = abs((q.w - q.y) / (6.0 * c + e) + q.z);
-    float l = v - c * 0.5;
-    float s = c / (1.0 - abs(2.0 * l - 1.0) + e);
-    return clamp(vec3(h, s, l), 0.0, 1.0);
-}
-
-vec3 hsl2rgb(vec3 hsl)
-{
-    vec3 h = vec3(hsl.x * 6.0);
-    vec3 p = abs(h - vec3(3.0, 2.0, 4.0));
-    vec3 q = 2.0 - p;
-
-    vec3 rgb = clamp(vec3(p.x - 1.0, q.yz), 0.0, 1.0);
-    float c = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;
-    return (rgb - vec3(0.5)) * c + hsl.z;
-}
-
 void main()
 {
     vec4 color = texture2D(texUnit, UV);
-    vec3 hsl = rgb2hsl(color.xyz);
-    vec3 rgb = pow(hsl2rgb(vec3(hsl.x, hsl.y * saturation, hsl.z * opacity)), vec3(gamma));
+    vec3 rgb = pow(color.rgb * opacity, vec3(gamma));
     gl_FragColor = vec4(rgb, 1.0);
 }
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index e33cfc1..1bb3417 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kon nie die kortpad teruglaai nie omdat die program nie rugsteun en teruglaai steun nie"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kon nie teruglaai nie omdat programondertekening nie ooreenstem nie"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kon nie kortpad teruglaai nie"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index e992266..0a996ca 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"መተግበሪያ ምትኬን እና ወደ ነበረበት መመለስን ሳለማይደግፍ አቋራጭ ወደ ነበረበት ሊመለስ አልቻለም"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"በመተግበሪያ ፊርማ አለመዛመድ አቋራጭን ወደነበረበት መመለስ አልተቻለም"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"አቋራጭን ወደ ነበረበት መመለስ አልተቻለም"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 2002084..e929bf8 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -51,7 +51,7 @@
     <string name="needPuk2" msgid="4526033371987193070">"‏اكتب PUK2 لإلغاء تأمين شريحة SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"‏محاولة غير ناجحة، مكّن قفل SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
-      <item quantity="zero">‏لم يتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدها قفل شريحة SIM.</item>
+      <item quantity="zero">‏لم يتبق لديك أي محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدها قفل شريحة SIM.</item>
       <item quantity="two">‏يتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدهما قفل شريحة SIM.</item>
       <item quantity="few">‏يتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات يتم بعدها قفل شريحة SIM.</item>
       <item quantity="many">‏يتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة يتم بعدها قفل شريحة SIM.</item>
@@ -448,9 +448,9 @@
     <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"يتيح للتطبيق تغيير المنطقة الزمنية للتلفزيون."</string>
     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"للسماح للتطبيق بتغيير المنطقة الزمنية للهاتف."</string>
     <string name="permlab_getAccounts" msgid="1086795467760122114">"البحث عن حسابات على الجهاز"</string>
-    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"للسماح للتطبيق بالحصول على قائمة بالحسابات التي يعرفها الجهاز اللوحي. وقد يتضمن ذلك أية حسابات تم إنشاؤها بواسطة التطبيقات التي ثبتها."</string>
-    <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"يتيح للتطبيق الحصول على قائمة بالحسابات المعروفة في التلفزيون. وقد يتضمن هذا أية حسابات أنشأتها التطبيقات التي ثبتها."</string>
-    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"للسماح للتطبيق بالحصول على قائمة بالحسابات التي يعرفها الهاتف. وقد يتضمن ذلك أية حسابات تم إنشاؤها بواسطة التطبيقات التي ثبتها."</string>
+    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"للسماح للتطبيق بالحصول على قائمة بالحسابات التي يعرفها الجهاز اللوحي. وقد يتضمن ذلك أي حسابات تم إنشاؤها بواسطة التطبيقات التي ثبتها."</string>
+    <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"يتيح للتطبيق الحصول على قائمة بالحسابات المعروفة في التلفزيون. وقد يتضمن هذا أي حسابات أنشأتها التطبيقات التي ثبتها."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"للسماح للتطبيق بالحصول على قائمة بالحسابات التي يعرفها الهاتف. وقد يتضمن ذلك أي حسابات تم إنشاؤها بواسطة التطبيقات التي ثبتها."</string>
     <string name="permlab_accessNetworkState" msgid="4951027964348974773">"عرض اتصالات الشبكة"</string>
     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"للسماح للتطبيق بعرض معلومات حول اتصالات الشبكة كعرض معلومات عن الشبكات المتوفرة والشبكات المتصلة."</string>
     <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"حق الوصول الكامل إلى الشبكة"</string>
@@ -472,7 +472,7 @@
     <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"يتيح للتطبيق تهيئة تلفزيون بلوتوث المحلي، واكتشاف الأجهزة البعيدة وإقرانها."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"للسماح للتطبيق بتهيئة هاتف البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
     <string name="permlab_accessWimaxState" msgid="4195907010610205703">"‏الاتصال بـشبكة WiMAX وقطع الاتصال بها"</string>
-    <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"‏للسماح للتطبيق بتحديد ما إذا تم تمكين WiMAX وتحديد معلومات حول أية شبكات WiMAX متصلة."</string>
+    <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"‏للسماح للتطبيق بتحديد ما إذا تم تمكين WiMAX وتحديد معلومات حول أي شبكات WiMAX متصلة."</string>
     <string name="permlab_changeWimaxState" msgid="340465839241528618">"‏تغيير حالة WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"‏للسماح للتطبيق بتوصيل الجهاز اللوحي بشبكات WiMAX وقطع اتصاله بها."</string>
     <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"‏يتيح للتطبيق توصيل التلفزيون أو إلغاء توصيله بشبكات WiMAX."</string>
@@ -817,7 +817,7 @@
     <string name="granularity_label_line" msgid="5764267235026120888">"سطر"</string>
     <string name="factorytest_failed" msgid="5410270329114212041">"تعذّر اختبار المصنع"</string>
     <string name="factorytest_not_system" msgid="4435201656767276723">"‏إجراء FACTORY_TEST غير متاح سوى للحزم المثبتة في /system/app."</string>
-    <string name="factorytest_no_action" msgid="872991874799998561">"‏لم يتم العثور على أية حزمة توفر إجراء FACTORY_TEST."</string>
+    <string name="factorytest_no_action" msgid="872991874799998561">"‏لم يتم العثور على أي حزمة توفر إجراء FACTORY_TEST."</string>
     <string name="factorytest_reboot" msgid="6320168203050791643">"إعادة تشغيل"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"تعرض الصفحة في \"<xliff:g id="TITLE">%s</xliff:g>\":"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"جافا سكريبت"</string>
@@ -1186,7 +1186,7 @@
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"أصوات الإشعار"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"غير معروف"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="zero">‏لا تتوفر أية شبكات Wi-Fi</item>
+      <item quantity="zero">‏لا تتوفر أي شبكات Wi-Fi</item>
       <item quantity="two">‏تتوفر شبكتا Wi-Fi</item>
       <item quantity="few">‏تتوفر شبكات Wi-Fi</item>
       <item quantity="many">‏تتوفر شبكات Wi-Fi</item>
@@ -1194,7 +1194,7 @@
       <item quantity="one">‏تتوفر شبكة Wi-Fi واحدة</item>
     </plurals>
     <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="zero">‏لا تتوفر أية شبكات Wi-Fi مفتوحة</item>
+      <item quantity="zero">‏لا تتوفر أي شبكات Wi-Fi مفتوحة</item>
       <item quantity="two">‏تتوفر شبكتا Wi-Fi مفتوحتان</item>
       <item quantity="few">‏تتوفر شبكات Wi-Fi مفتوحة</item>
       <item quantity="many">‏تتوفر شبكات Wi-Fi مفتوحة</item>
@@ -1413,7 +1413,7 @@
     <string name="back_button_label" msgid="2300470004503343439">"رجوع"</string>
     <string name="next_button_label" msgid="1080555104677992408">"التالي"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"تخطي"</string>
-    <string name="no_matches" msgid="8129421908915840737">"ليس هناك أية مطابقات"</string>
+    <string name="no_matches" msgid="8129421908915840737">"ليس هناك أي مطابقات"</string>
     <string name="find_on_page" msgid="1946799233822820384">"بحث في الصفحة"</string>
     <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
       <item quantity="zero"><xliff:g id="INDEX">%d</xliff:g> من <xliff:g id="TOTAL">%d</xliff:g></item>
@@ -1947,4 +1947,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"تعذّرت استعادة الاختصار لأن التطبيق لا يوفِّر إمكانية النسخ الاحتياطي والاستعادة"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"تعذّرت استعادة الاختصار بسبب عدم تطابق توقيع التطبيق"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"تعذّرت استعادة الاختصار"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index a05d49f..8069d6c 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Qısayolu bərpa etmək mümkün olmadı, çünki tətbiq yedəkləməni və bərpa etməyi dəstəkləmir"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tətbiqin imza uyğunsuzluğu səbəbilə qısayolu bərpa etmək mümkün olmadı"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Qısayolu bərpa etmək mümkün olmadı"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index ce220db..bb5a404 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1842,4 +1842,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Vraćanje prečice nije uspelo jer aplikacija ne podržava pravljenje rezervne kopije i vraćanje"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Vraćanje prečice nije uspelo jer se potpisi aplikacija ne podudaraju"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Vraćanje prečice nije uspelo"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index f636f48..b5e28b3 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не атрымалася аднавіць ярлык, бо праграма не падтрымлівае рэзервовае капіраванне і аднаўленне"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не атрымалася аднавіць ярлык з-за несупадзення подпісаў праграм"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не атрымалася аднавіць ярлык"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 7a37939..e069c4e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Прекият път не можа да бъде възстановен, защото приложението не поддържа създаването на резервно копие и възстановяването"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Прекият път не можа да бъде възстановен поради несъответствие в подписа на приложението"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Прекият път не можа да бъде възстановен"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index b88d2c8..9b1f6c3 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"শর্টকাট ফিরিয়ে আনা যায়নি কারণ অ্যাপটিতে \'ব্যাক-আপ এবং রিস্টোর\' করার সুবিধা নেই"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"শর্টকাট ফিরিয়ে আনা যায়নি কারণ অ্যাপের সিগ্নেচারটি মিল হচ্ছে না"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"শর্টকাট ফিরিয়ে আনা যায়নি"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index e19a974..c79566b 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1844,4 +1844,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Prečica nije uspješno vraćena jer aplikacija ne podržava izradu sigurnosne kopije i vraćanje"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Prečica nije uspješno vraćena zbog nepodudaranja potpisa aplikacije"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Prečica nije uspješno vraćena"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 7e109ac..ea09008 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"No s\'ha pogut restaurar la drecera perquè l\'aplicació no permet la còpia de seguretat ni la restauració"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"No s\'ha pogut restaurar la drecera perquè la signatura de l\'aplicació no coincideix"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"No s\'ha pogut restaurar la drecera"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8b0e46e..684c257 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Zkratku nelze obnovit, protože aplikace nepodporuje zálohování a obnovu"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Zkratku nelze obnovit, protože se neshoduje podpis aplikace"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Zkratku nelze obnovit"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0be9d20..90b7e5e 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Genvejen kunne ikke gendannes, da appen ikke understøtter backup og gendannelse"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Genvejen kunne ikke gendannes på grund af uoverensstemmelse i appsignatur"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Genvejen kunne ikke gendannes"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 367949c..9d317eb 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Verknüpfung konnte nicht wiederhergestellt werden, weil die App keine Sicherung und keine Wiederherstellung unterstützt"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Verknüpfung konnte nicht wiederhergestellt werden, weil die App-Signatur nicht übereinstimmt"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Verknüpfung konnte nicht wiederhergestellt werden"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 05c51cf..9aa3eb5 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης, επειδή η εφαρμογή δεν υποστηρίζει τη δημιουργία αντιγράφων ασφαλείας και την επαναφορά"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης, λόγω αναντιστοιχίας της υπογραφής εφαρμογής"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index ed97563..700641e 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index ed97563..700641e 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ed97563..700641e 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index ed97563..700641e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 2833630..ba21245 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‎Couldn’t restore shortcut because app doesn’t support backup and restore‎‏‎‎‏‎"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‎‎Couldn’t restore shortcut because of app signature mismatch‎‏‎‎‏‎"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎Couldn’t restore shortcut‎‏‎‎‏‎"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 3efbad9..1fe3c9a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Error al restablecer el acceso directo porque la app no admite la opción de copia de seguridad y restauración"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Error al restablecer el acceso directo por falta de coincidencia con la firma de apps"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Error al restablecer el acceso directo"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 5a0a118..cf25ed3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -453,7 +453,7 @@
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Permite que la aplicación se conecte a puntos de acceso Wi-Fi y se desconecte de ellos y que realice cambios en la configuración de redes Wi-Fi del dispositivo."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepción multidifusión Wi-Fi"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos de una red Wi-Fi que utilicen direcciones de multidifusión, no solo al tablet. Utiliza más batería que el modo de no multidifusión."</string>
-    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos a través de una red Wi-Fi mediante direcciones de multidifusión, no solo la TV. Consume más energía que el modo sin multidifusión."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos a través de una red Wi-Fi mediante direcciones de multidifusión, no solo la TV. Consume más batería que el modo sin multidifusión."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos de una red Wi-Fi que utilicen direcciones de multidifusión, no solo al teléfono. Utiliza más batería que el modo de no multidifusión."</string>
     <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"acceder a los ajustes de Bluetooth"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite que la aplicación configure el tablet Bluetooth local y que detecte dispositivos remotos y se vincule con ellos."</string>
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"No se ha podido restaurar el acceso directo porque la aplicación no es compatible con la función de copia de seguridad y restauración"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"No se ha podido restaurar el acceso directo porque la firma de la aplicación no coincide"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"No se ha podido restaurar el acceso directo"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4b2d13b..c0821c7 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Otseteed ei õnnestunud taastada, kuna rakendus ei toeta varundamist ega taastamist"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Otseteed ei õnnestunud taastada, kuna rakenduse allkiri ei ühti"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Otseteed ei õnnestunud taastada"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index f468b5d..100ed1e 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -294,7 +294,7 @@
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Eskuratu leihoko edukia"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Arakatu irekita daukazun leihoko edukia."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktibatu \"Arakatu ukituta\""</string>
-    <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Sakatutako elementuak ozen esango dira eta pantaila keinu bidez arakatu ahal izango da."</string>
+    <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Sakatutako elementuak ozen irakurriko dira eta pantaila keinu bidez arakatu ahal izango da."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Behatu idazten duzun testua"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Ez da salbuespenik egiten datu pertsonalekin, hala nola, kreditu-txartelen zenbakiekin eta pasahitzekin."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrolatu pantailaren zoom-maila"</string>
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ezin izan da leheneratu lasterbidea aplikazioak ez duelako onartzen babeskopiak egiteko eta leheneratzeko aukera"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ezin izan da leheneratu lasterbidea aplikazioaren sinadurak ez datozelako bat"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ezin izan da leheneratu lasterbidea"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 8061962..0458336 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"نمی‌توان میان‌بر را بازیابی کرد زیرا برنامه از پشتیبان‌گیری و بازیابی پشتیبانی نمی‌کند"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"به‌علت عدم تطابق امضای برنامه نمی‌توان میان‌بر را بازیابی کرد"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"نمی‌توان میان‌بر را بازیابی کرد"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 4385466..d6d1315 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Pikakuvakkeen palautus epäonnistui, koska sovellus ei tue varmuuskopiointia eikä palauttamista."</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Pikakuvakkeen palautus epäonnistui sovelluksen allekirjoituksen yhteensopimattomuuden vuoksi."</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Pikakuvakkeen palautus epäonnistui."</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 49a3640..9af3ed7 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossible de restaurer le raccourci, car l\'application ne prend pas en charge la sauvegarde et la restauration"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossible de restaurer le raccourci en raison d\'une erreur de correspondance des signature d\'applications"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 5564d8b..97cc0ec 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Le raccourci ne peut pas être restauré car l\'application n\'accepte pas la sauvegarde et la restauration"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Le raccourci ne peut pas être restauré car la signature de l\'application est différente"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 40dff7e..a53fac7 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -133,7 +133,7 @@
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivado"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wifi preferida"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Datos móbiles preferidos"</string>
-    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Só wifi"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Só por wifi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non desviada"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> tras <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Non se puido restaurar o atallo porque a aplicación non é compatible coa restauración e a copia de seguranza"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Non se puido restaurar o atallo porque a sinatura da aplicación non coincide"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Non se puido restaurar o atallo"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 7a4c1b2..81e5f4f 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપ બૅકઅપ અને ફરી મેળવવાનું સમર્થન કરતી નથી"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપમાં છે તે સહી મેળ ખાતી નથી"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"શૉર્ટકટ પાછો મેળવી શકાયો નથી"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index adeba4e..2349583 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"शॉर्टकट बहाल नहीं किया जा सका क्योंकि इस ऐप में बैकअप लेने और उसे बहाल करने की सुविधा नहीं है"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ऐप सिग्नेचर अलग होने के कारण शॉर्टकट बहाल नहीं किया जा सका"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"शॉर्टकट बहाल नहीं किया जा सका"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6883769..bbe7ca9 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1842,4 +1842,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Vraćanje prečaca nije uspjelo jer aplikacija ne podržava sigurnosno kopiranje i vraćanje"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Vraćanje prečaca nije uspjelo zbog nepodudaranja potpisa aplikacije"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Vraćanje prečaca nije uspjelo"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 2545283..2dbe49d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nem sikerült visszaállítani a parancsikont, mert az alkalmazás nem támogatja a biztonsági mentést és visszaállítást"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nem sikerült visszaállítani a parancsikont, mert az alkalmazás-aláírás nem egyezik"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nem sikerült visszaállítani a parancsikont"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index d29c357..1218b48 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածում չի աջակցվում պահուստավորման և վերականգնման գործառույթը"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածների ստորագրությունները տարբեր են"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Չհաջողվեց վերականգնել դյուրանցումը"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d5d8d99..cb2b8a5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Tidak dapat memulihkan pintasan karena aplikasi tidak mendukung backup dan pulihkan"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tidak dapat memulihkan pintasan karena tanda tangan aplikasi tidak cocok"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Tidak dapat memulihkan pintasan."</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index b65da75..40bf34c 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ekki var hægt að endurheimta flýtileið vegna þess að forritið styður ekki öryggisafritun og endurheimt"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ekki var hægt að endurheimta flýtileið vegna þess að undirskriftir forrita passa ekki saman"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ekki var hægt að endurheimta flýtileið"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0f36301..3c9745f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossibile ripristinare la scorciatoia perché l\'app non supporta il backup e il ripristino"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossibile ripristinare la scorciatoia perché la firma dell\'app non corrisponde"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossibile ripristinare la scorciatoia"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a152840..7c0ce3a 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"לא ניתן היה לשחזר את קיצור הדרך מפני שהאפליקציה אינה תומכת בגיבוי ובשחזור"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"לא ניתן היה לשחזר את קיצור הדרך עקב חוסר התאמה בחתימה על האפליקציות"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"לא ניתן היה לשחזר את קיצור הדרך"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 2f11776..2fb35f8 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"このアプリはバックアップと復元に対応していないため、ショートカットを復元できませんでした"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"アプリの署名が一致しないため、ショートカットを復元できませんでした"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ショートカットを復元できませんでした"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 40e9414..45ed466 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"მალსახმობის აღდგენა ვერ მოხერხდა, რადგან ამ აპის მიერ მხარდაუჭერელია სარეზერვო ასლით აღდგენა"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"მალსახმობის აღდგენა ვერ მოხერხდა აპის ხელმოწერის შეუსაბამობის გამო"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"მალსახმობის აღდგენა ვერ მოხერხდა"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index d428ff0..51c5147 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Қолданба сақтық көшірме жасау мен қалпына келтіруді қолдамайтындықтан, таңбаша қалпына келтірілмеді"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Қолтаңба сәйкес келмейтіндіктен, таңбаша қалпына келтірілмеді"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Таңбаша қалпына келтірілмеді"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 889ea5e..c266416 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1809,4 +1809,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"មិនអាចស្តារផ្លូវកាត់បានទេ ដោយសារកម្មវិធីមិនស្គាល់ការបម្រុងទុក និងការស្តារ"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"មិនអាចស្តារផ្លូវកាត់បានទេ ដោយសារការស៊ីញ៉េកម្មវិធីមិនត្រូវគ្នា"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"មិនអាចស្តារផ្លូវកាត់បានទេ"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index d751c13..2fe14dc 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ಅಪ್ಲಿಕೇಶನ್‌ ಬ್ಯಾಕಪ್ ಮತ್ತು ಪುನಃಸ್ಥಾಪನೆಯನ್ನು ಬೆಂಬಲಿಸದಿರುವುದರಿಂದ ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಪುನಃಸ್ಥಾಪನೆ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ಅಪ್ಲಿಕೇಶನ್‌ ಸಹಿ ಹೊಂದಿಕೆಯಾಗದ ಕಾರಣದಿಂದ ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಪುನಃಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಪುನಃ ಸ್ಥಾಪನೆ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 922f02f..221a233 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"앱이 백업 및 복원을 지원하지 않으므로 바로가기를 복원할 수 없습니다"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"앱 서명이 일치하지 않아 바로가기를 복원할 수 없습니다"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"바로가기를 복원할 수 없습니다"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index f3f7222..1bce491 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1809,4 +1809,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Колдонмо камдык көчүрмөнү сактоо жана калыбына келтирүү функцияларын колдобогондуктан кыска жол калыбына келтирилбей койду"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Колдонмонун колтамгасы дал келбегендиктен кыска жол калыбына келтирилбей койду"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Кыска жол калыбына келтирилбей койду"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index bc7e339..9f7a28f 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ບໍ່ສາມາດກູ້ທາງລັດຂຶ້ນມາໄດ້ເນື່ອງຈາກແອັບບໍ່ຮອງຮັບການສຳຮອງ ແລະ ກູ້ຂໍ້ມູນ"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ບໍ່ສາມາດກູ້ທາງລັດຄືນມາໄດ້ເນື່ອງຈາກລາຍເຊັນແອັບບໍ່ກົງກັນ"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ບໍ່ສາມາດກູ້ທາງລັດຄືນມາໄດ້"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 2f5014e..57745c2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nepavyko atkurti sparčiojo klavišo, nes programa nepalaiko atsarginės kopijos kūrimo ir atkūrimo funkcijų"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nepavyko atkurti sparčiojo klavišo, nes programos parašas neatitinka"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nepavyko atkurti sparčiojo klavišo"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index c2199a8..2d98ade 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1842,4 +1842,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nevarēja atjaunot saīsni, jo lietotnē netiek atbalstīta dublēšana un atjaunošana."</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Saīsni nevarēja atjaunot lietotnes paraksta neatbilstības dēļ."</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nevarēja atjaunot saīsni."</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mcc204-mnc04/config.xml b/core/res/res/values-mcc204-mnc04/config.xml
index c66ed12..4a3bf22 100755
--- a/core/res/res/values-mcc204-mnc04/config.xml
+++ b/core/res/res/values-mcc204-mnc04/config.xml
@@ -25,15 +25,5 @@
     -->
     <integer name="config_mobile_mtu">1358</integer>
 
-    <!--Thresholds for LTE dbm in status bar-->
-    <integer-array translatable="false" name="config_lteDbmThresholds">
-        <item>-140</item>    <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
-        <item>-115</item>    <!-- SIGNAL_STRENGTH_POOR -->
-        <item>-105</item>    <!-- SIGNAL_STRENGTH_MODERATE -->
-        <item>-95</item>     <!-- SIGNAL_STRENGTH_GOOD -->
-        <item>-85</item>     <!-- SIGNAL_STRENGTH_GREAT -->
-        <item>-44</item>
-    </integer-array>
-
     <string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true;BAE0000000000000</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 04f182e..cc7daa8 100755
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -51,16 +51,6 @@
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
 
-    <!--Thresholds for LTE dbm in status bar-->
-    <integer-array translatable="false" name="config_lteDbmThresholds">
-        <item>-140</item>    <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
-        <item>-115</item>    <!-- SIGNAL_STRENGTH_POOR -->
-        <item>-105</item>    <!-- SIGNAL_STRENGTH_MODERATE -->
-        <item>-95</item>     <!-- SIGNAL_STRENGTH_GOOD -->
-        <item>-85</item>     <!-- SIGNAL_STRENGTH_GREAT -->
-        <item>-44</item>
-    </integer-array>
-
     <string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true</string>
 
     <bool name="config_use_sim_language_file">true</bool>
diff --git a/core/res/res/values-mcc505-mnc01/config.xml b/core/res/res/values-mcc505-mnc01/config.xml
index 5a5b8f7..bc088d1 100644
--- a/core/res/res/values-mcc505-mnc01/config.xml
+++ b/core/res/res/values-mcc505-mnc01/config.xml
@@ -31,16 +31,6 @@
       <item>9</item>
     </integer-array>
 
-    <!--Thresholds for LTE dbm in status bar-->
-    <integer-array translatable="false" name="config_lteDbmThresholds">
-        <item>-140</item>    <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
-        <item>-120</item>    <!-- SIGNAL_STRENGTH_POOR -->
-        <item>-115</item>    <!-- SIGNAL_STRENGTH_MODERATE -->
-        <item>-100</item>    <!-- SIGNAL_STRENGTH_GOOD -->
-        <item>-90</item>     <!-- SIGNAL_STRENGTH_GREAT -->
-        <item>-44</item>
-    </integer-array>
-
     <!-- Configure mobile network MTU. Carrier specific value is set here.
     -->
     <integer name="config_mobile_mtu">1400</integer>
diff --git a/core/res/res/values-mcc505-mnc11/config.xml b/core/res/res/values-mcc505-mnc11/config.xml
deleted file mode 100644
index 6d085c1..0000000
--- a/core/res/res/values-mcc505-mnc11/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!--Thresholds for LTE dbm in status bar-->
-    <integer-array translatable="false" name="config_lteDbmThresholds">
-        <item>-140</item>    <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
-        <item>-120</item>    <!-- SIGNAL_STRENGTH_POOR -->
-        <item>-115</item>    <!-- SIGNAL_STRENGTH_MODERATE -->
-        <item>-100</item>    <!-- SIGNAL_STRENGTH_GOOD -->
-        <item>-90</item>     <!-- SIGNAL_STRENGTH_GREAT -->
-        <item>-44</item>
-    </integer-array>
-</resources>
diff --git a/core/res/res/values-mcc505-mnc71/config.xml b/core/res/res/values-mcc505-mnc71/config.xml
deleted file mode 100644
index 6d085c1..0000000
--- a/core/res/res/values-mcc505-mnc71/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!--Thresholds for LTE dbm in status bar-->
-    <integer-array translatable="false" name="config_lteDbmThresholds">
-        <item>-140</item>    <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
-        <item>-120</item>    <!-- SIGNAL_STRENGTH_POOR -->
-        <item>-115</item>    <!-- SIGNAL_STRENGTH_MODERATE -->
-        <item>-100</item>    <!-- SIGNAL_STRENGTH_GOOD -->
-        <item>-90</item>     <!-- SIGNAL_STRENGTH_GREAT -->
-        <item>-44</item>
-    </integer-array>
-</resources>
diff --git a/core/res/res/values-mcc505-mnc72/config.xml b/core/res/res/values-mcc505-mnc72/config.xml
deleted file mode 100644
index 6d085c1..0000000
--- a/core/res/res/values-mcc505-mnc72/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!--Thresholds for LTE dbm in status bar-->
-    <integer-array translatable="false" name="config_lteDbmThresholds">
-        <item>-140</item>    <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
-        <item>-120</item>    <!-- SIGNAL_STRENGTH_POOR -->
-        <item>-115</item>    <!-- SIGNAL_STRENGTH_MODERATE -->
-        <item>-100</item>    <!-- SIGNAL_STRENGTH_GOOD -->
-        <item>-90</item>     <!-- SIGNAL_STRENGTH_GREAT -->
-        <item>-44</item>
-    </integer-array>
-</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index e1e2b43..67aabea 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1810,4 +1810,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не можеше да се врати кратенката бидејќи апликацијата не поддржува бекап и враќање"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не можеше да се врати кратенката бидејќи потписот на апликацијата не се совпаѓа"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не можеше да се врати кратенката"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 6a8cea1..69c0fed 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ആപ്പ് \'ബാക്കപ്പും പുനഃസ്ഥാപിക്കലും\' പിന്തുണയ്ക്കാത്തതിനാൽ കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ആപ്പ് സിഗ്നേച്ചർ പൊരുത്തപ്പെടാത്തതിനാൽ കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 53740f94..dbbb29e 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1805,4 +1805,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Апп нөөцлөлт, сэргээлтийг дэмждэггүй тул товчлолыг сэргээж чадсангүй"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Аппын гарын үсэг таарахгүй байгаа тул товчлолыг сэргээж чадсангүй"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Товчлолыг сэргээж чадсангүй"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 398ad0d..addb2d1 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"अॅप बॅकअप आणि रिस्‍टोअर करण्यास सपोर्ट देत नसल्यामुळे शॉर्टकट रिस्‍टोअर करू शकलो नाही"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"अॅप स्वाक्षरी न जुळल्यामुळे शॉर्टकट रिस्‍टोअर करू शकलो नाही"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"शॉर्टकट रिस्‍टोअर करू शकलो नाही"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 574c775..f7e18ff 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Tidak dapat memulihkan pintasan kerana apl tidak menyokong sandaran dan segerakan"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tidak dapat memulihkan pintasan kerana ketakpadanan tandatangan apl"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Tidak dapat memulihkan pintasan"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 9dc49cf..1777b26 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"အက်ပ်သည် မိတ္တူကူးခြင်းနှင့် ပြန်ယူခြင်းကို ပံ့ပိုးခြင်းမရှိသည့်အတွက် ဖြတ်လမ်းလင့်ခ်ကို ပြန်ယူ၍မရပါ"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"အက်ပ်လက်မှတ် မတူညီသည့်အတွက် ဖြတ်လမ်းလင့်ခ်များကို ပြန်ယူ၍မရပါ"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ဖြတ်လမ်းလင့်ခ်ကို ပြန်ယူ၍မရပါ"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d360fa4..873967a 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kunne ikke gjenopprette snarveien fordi appen ikke støtter sikkerhetskopiering og gjenoppretting"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kunne ikke gjenopprette snarveien på grunn av manglende samsvar for appsignaturen"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kunne ikke gjenopprette snarveien"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 3d05239..3e0e04b 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1813,4 +1813,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"अनुप्रयोगले ब्याकअप तथा पुनर्स्थापनालाई समर्थन नगर्ने हुँदा सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"अनुप्रयोगमा प्रयोग गरिने हस्ताक्षर नमिल्ने हुँदा सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 725fe8e..1d8619c 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kan snelkoppeling niet herstellen omdat de app geen ondersteuning biedt voor \'Back-up maken en terugzetten\'"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kan snelkoppeling niet herstellen vanwege een niet-overeenkomende app-ondertekening"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kan snelkoppeling niet herstellen"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index cf90550..b08b1b2 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ ਕਿਉਂਕਿ ਐਪ \'ਬੈਕਅੱਪ ਅਤੇ ਮੁੜ-ਬਹਾਲੀ\' ਨਾਲ ਕੰਮ ਨਹੀਂ ਕਰਦੀ"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ਐਪ ਹਸਤਾਖਰ ਦਾ ਮੇਲ ਨਾ ਹੋਣ ਕਾਰਨ ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 412d5a7..108b87b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nie można przywrócić skrótu, bo aplikacja nie obsługuje tworzenia i przywracania kopii zapasowej"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nie można przywrócić skrótu z powodu niezgodności podpisu aplikacji"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nie można przywrócić skrótu"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index bf83d77..35cbd28 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque o app não é compatível com backup e restauração"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido à incompatibilidade de assinatura de apps"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 31b67a0..a9a4a91 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque a aplicação não é compatível com a funcionalidade de cópia de segurança e restauro."</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido a uma falha de correspondência entre as assinaturas das aplicações."</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho."</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bf83d77..35cbd28 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque o app não é compatível com backup e restauração"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido à incompatibilidade de assinatura de apps"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4f15c33..0104894 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1842,4 +1842,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nu s-a putut restabili comanda rapidă deoarece aplicația nu acceptă backupul și restabilirea"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nu s-a putut restabili comanda rapidă din cauza nepotrivirii semnăturii aplicației"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nu s-a putut restabili comanda rapidă"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 60ad441..460e0c7 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не удалось восстановить ярлык: приложение не поддерживает резервное копирование"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не удалось восстановить ярлык: некорректная подпись приложения"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не удалось восстановить ярлык"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 5b0eda3..4188a41 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1809,4 +1809,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"යෙදුම උපස්ථ සහ ප්‍රතිසාධනය සඳහා සහාය නොදක්වන බැවින් කෙටි මග ප්‍රතිසාධනය කළ නොහැකි විය"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"යෙදුම් අත්සන නොගැළපෙන බැවින් කෙටි මග ප්‍රතිසාධනය කළ නොහැකි විය"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"කෙටි මග ප්‍රතිසාධනය කළ නොහැකි විය"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 1f11fb4..1fb90ff 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Odkaz sa nepodarilo obnoviť, pretože aplikácia nepodporuje zálohovanie a obnovu"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Odkaz sa nepodarilo obnoviť pre nesúlad podpisov aplikácie"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Odkaz sa nepodarilo obnoviť"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e8f89a5..df3c3e7 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Bližnjice ni bilo mogoče obnoviti, ker aplikacija ne podpira varnostnega kopiranja in obnavljanja"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Bližnjice ni bilo mogoče obnoviti zaradi neujemanja podpisa aplikacije"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Bližnjice ni bilo mogoče obnoviti"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index a03ac24..e6d60d4 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nuk mund të restaurohej shkurtorja sepse aplikacioni nuk mbështet rezervimin dhe restaurimin"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nuk mund të restaurohej shkurtorja për shkak të mospërputhjes së nënshkrimit të aplikacionit"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nuk mund të restaurohej shkurtorja"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 8bec119..275db37 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1842,4 +1842,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Враћање пречице није успело јер апликација не подржава прављење резервне копије и враћање"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Враћање пречице није успело јер се потписи апликација не подударају"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Враћање пречице није успело"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 1f590d3..1633e43 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1205,7 +1205,7 @@
     <string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Ett tillbehör med analog ljudutgång hittades"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Den anslutna enheten är inte kompatibel med mobilen. Tryck här om du vill veta mer."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
-    <string name="adb_active_notification_message" msgid="4948470599328424059">"Tryck om du vill inaktivera USB-felsökning."</string>
+    <string name="adb_active_notification_message" msgid="4948470599328424059">"Tryck för att inaktivera USB-felsökning."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Välj för att inaktivera USB-felsökning."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Felrapporten överförs …"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vill du dela felrapporten?"</string>
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Det gick inte att återställa genvägen eftersom appen inte har stöd för säkerhetskopiering och återställning"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Det gick inte att återställa genvägen eftersom appens signatur inte stämmer"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Det gick inte att återställa genvägen"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index bd8b029..b98a5c7 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1805,4 +1805,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Imeshindwa kurejesha njia ya mkato kwa sababu programu haitumii kipengele cha hifadhi rudufu na kurejesha upya"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Imeshindwa kurejesha njia ya mkato kwa sababu ufunguo wako wa kuambatisha cheti kwenye programu haulingani"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Imeshindwa kurejesha njia ya mkato"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 6d247f4..6014de4 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"காப்புப் பிரதி மற்றும் மீட்டமைவைப் பயன்பாடு ஆதரிக்காத காரணத்தால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"பயன்பாட்டுச் சான்றுகள் பொருந்தாத காரணத்தினால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index d39467b..a04c529 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"బ్యాకప్ మరియు పునరుద్ధరణకు యాప్ మద్దతు ఇవ్వని కారణంగా సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"యాప్ సంతకం సరిపోలని కారణంగా సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1bea4e4..d9a504b 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"คืนค่าทางลัดไม่ได้เนื่องจากแอปไม่รองรับการสำรองข้อมูลและคืนค่า"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"คืนค่าทางลัดไม่ได้เนื่องจากการลงนามแอปไม่ตรงกัน"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"คืนค่าทางลัดไม่ได้"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 2bc5780..98e169e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Hindi ma-restore ang shortcut dahil hindi sinusuportahan ng app ang pag-back up at pag-restore"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Hindi ma-restore ang shortcut dahil hindi magkatugma ang signature ng app"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Hindi ma-restore ang shortcut"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 337d458..e2b1cb3 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Uygulama, yedekleme ve geri yüklemeyi desteklemediğinden kısayol geri yüklenemedi"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Uygulama imzası eşleşmediğinden kısayol geri yüklenemedi"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kısayol geri yüklenemedi"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5344dcf..788444e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1877,4 +1877,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не вдалося відновити ярлик, оскільки додаток не підтримує резервне копіювання та відновлення"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не вдалося відновити ярлик, оскільки підписи додатків не збігаються"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не вдалося відновити ярлик"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 4ced9cf..38313d6 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"شارٹ کٹ کو بحال نہیں کیا جا سکا، کیونکہ ایپ بیک اپ اور بحالی کو سپورٹ نہیں کرتی ہے"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ایپ دستخط غیر مماثل ہونے کی وجہ سے شارٹ کٹ کو بحال نہیں کیا جا سکا"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"شارٹ کٹ کو بحال نہیں کیا جا سکا"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d7d3941..92ec354 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1808,4 +1808,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ilovada zaxiralash va tiklash ishlamagani uchun yorliq tiklanmadi"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ilova imzosi mos kelmagani uchun yorliq tiklanmadi"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Yorliq tiklanmadi"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c5a370a..f5a1972 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Không thể khôi phục lối tắt do ứng dụng không hỗ trợ sao lưu và khôi phục"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Không thể khôi phục lối tắt do không khớp chữ ký ứng dụng"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Không thể khôi phục lối tắt"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index e8ad015..70b299e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"无法恢复快捷方式,因为应用不支持备份和恢复功能"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"无法恢复快捷方式,因为应用签名不相符"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"无法恢复快捷方式"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index bedaef4..3dad724 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"由於應用程式不支援備份和還原功能,因此無法還原捷徑"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"由於應用程式簽署不相符,因此無法還原捷徑"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"無法還原捷徑"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 38109f8..d3ad7b0 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"應用程式不支援備份與還原功能,因此無法還原捷徑"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"應用程式簽署不相符,因此無法還原捷徑"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"無法還原捷徑"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 57b9fc3..e91e382 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1807,4 +1807,6 @@
     <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ayikwazanga ukubuyisa isinqamuleli ngoba uhlelo lokusebenza alusekeli isipele nokubuyisa"</string>
     <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ayikwazanga ukubuyisa isinqamuleli ngoba isignisha yohlelo lokusebenza ayifani"</string>
     <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ayikwazanga ukubuyisa isinqamuleli"</string>
+    <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ee7c795..addbbf5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3030,6 +3030,10 @@
              value, {@code false}, leaves the screen reader to consider other signals, such as
              focusability or the presence of text, to decide what it focus.-->
         <attr name="screenReaderFocusable" format="boolean" />
+
+        <!-- The title this view should present to accessibility as a pane title.
+             See {@link android.view.View#setAccessibilityPaneTitle(CharSequence)} -->
+        <attr name="accessibilityPaneTitle" format="string" />
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -7756,21 +7760,21 @@
         <attr name="settingsActivity" />
     </declare-styleable>
 
-    <!-- @SystemApi Use <code>trust-agent</code> as the root tag of the XML resource that
+    <!--  Use <code>trust-agent</code> as the root tag of the XML resource that
          describes an {@link android.service.trust.TrustAgentService}, which is
          referenced from its {@link android.service.trust.TrustAgentService#TRUST_AGENT_META_DATA}
          meta-data entry.  Described here are the attributes that can be included in that tag.
          @hide -->
     <declare-styleable name="TrustAgent">
-        <!-- @SystemApi Component name of an activity that allows the user to modify
+        <!--  Component name of an activity that allows the user to modify
              the settings for this trust agent. @hide -->
         <attr name="settingsActivity" />
-        <!-- @SystemApi Title for a preference that allows that user to launch the
+        <!--  Title for a preference that allows that user to launch the
              activity to modify trust agent settings. @hide -->
         <attr name="title" />
-        <!-- @SystemApi Summary for the same preference as the title. @hide -->
+        <!--  Summary for the same preference as the title. @hide -->
         <attr name="summary" />
-        <!-- @SystemApi Whether trust agent can unlock a user profile @hide -->
+        <!--  Whether trust agent can unlock a user profile @hide -->
         <attr name="unlockProfile" format="boolean"/>
     </declare-styleable>
 
@@ -7980,16 +7984,16 @@
          by the enrollment application.
          Described here are the attributes that can be included in that tag.
          @hide
-         @SystemApi -->
+          -->
     <declare-styleable name="VoiceEnrollmentApplication">
-        <!-- A globally unique ID for the keyphrase. @hide @SystemApi -->
+        <!-- A globally unique ID for the keyphrase. @hide  -->
         <attr name="searchKeyphraseId" format="integer" />
-        <!-- The actual keyphrase/hint text, or empty if not keyphrase dependent. @hide @SystemApi -->
+        <!-- The actual keyphrase/hint text, or empty if not keyphrase dependent. @hide  -->
         <attr name="searchKeyphrase" format="string" />
         <!-- A comma separated list of BCP-47 language tag for locales that are supported
-             for this keyphrase, or empty if not locale dependent. @hide @SystemApi -->
+             for this keyphrase, or empty if not locale dependent. @hide  -->
         <attr name="searchKeyphraseSupportedLocales" format="string" />
-        <!-- Flags for supported recognition modes. @hide @SystemApi -->
+        <!-- Flags for supported recognition modes. @hide  -->
         <attr name="searchKeyphraseRecognitionFlags">
             <flag name="none" value="0" />
             <flag name="voiceTrigger" value="0x1" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index efbe9c2..287f296 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2568,9 +2568,9 @@
              e.g. name=ro.oem.sku value=MKT210.
              Overlay will be ignored unless system property exists and is
              set to specified value -->
-        <!-- @hide @SystemApi This shouldn't be public. -->
+        <!-- @hide This shouldn't be public. -->
         <attr name="requiredSystemPropertyName" format="string" />
-        <!-- @hide @SystemApi This shouldn't be public. -->
+        <!-- @hide This shouldn't be public. -->
         <attr name="requiredSystemPropertyValue" format="string" />
     </declare-styleable>
 
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index fd78500..a078d8b 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -73,7 +73,7 @@
     <drawable name="editbox_dropdown_light_frame">@drawable/editbox_dropdown_background</drawable>
 
     <drawable name="input_method_fullscreen_background">#fff9f9f9</drawable>
-    <color name="input_method_navigation_guard">#ff000000</color>
+    <color name="decor_view_status_guard">#ff000000</color>
 
     <!-- For date picker widget -->
     <drawable name="selected_day_background">#ff0092f4</drawable>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 0413100..f8a77f8 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -77,9 +77,9 @@
     <item name="secondary_content_alpha_material_dark" format="float" type="dimen">.7</item>
     <item name="secondary_content_alpha_material_light" format="float" type="dimen">0.54</item>
 
-    <item name="highlight_alpha_material_light" format="float" type="dimen">0.12</item>
-    <item name="highlight_alpha_material_dark" format="float" type="dimen">0.20</item>
-    <item name="highlight_alpha_material_colored" format="float" type="dimen">0.26</item>
+    <item name="highlight_alpha_material_light" format="float" type="dimen">0.16</item>
+    <item name="highlight_alpha_material_dark" format="float" type="dimen">0.32</item>
+    <item name="highlight_alpha_material_colored" format="float" type="dimen">0.48</item>
 
     <!-- Primary & accent colors -->
     <eat-comment />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d2685cf..e3a910f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2481,6 +2481,7 @@
     <string-array translatable="false" name="config_globalActionsList">
         <item>power</item>
         <item>restart</item>
+        <item>screenshot</item>
         <item>logout</item>
         <item>bugreport</item>
         <item>users</item>
@@ -2667,6 +2668,13 @@
 
     <bool name="config_sms_force_7bit_encoding">false</bool>
 
+    <!-- Number of physical SIM slots on the device. This includes both eSIM and pSIM slots, and
+         is not necessarily the same as the number of phones/logical modems supported by the device.
+         For example, a multi-sim device can have 2 phones/logical modems, but 3 physical slots,
+         or a single SIM device can have 1 phones/logical modems, but 2 physical slots (one eSIM
+         and one pSIM) -->
+    <integer name="config_num_physical_slots">1</integer>
+
     <!--Thresholds for LTE dbm in status bar-->
     <integer-array translatable="false" name="config_lteDbmThresholds">
         <item>-140</item>    <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
@@ -2769,6 +2777,18 @@
          some existing device-specific resource overlays. -->
     <bool name="config_mainBuiltInDisplayIsRound">@bool/config_windowIsRound</bool>
 
+    <!-- The bounding path of the cutout region of the main built-in display.
+         Must either be empty if there is no cutout region, or a string that is parsable by
+         {@link android.util.PathParser}.
+         The path is assumed to be specified in display coordinates with pixel units and in
+         the display's native orientation. -->
+    <string translatable="false" name="config_mainBuiltInDisplayCutout"></string>
+
+    <!-- Whether the display cutout region of the main built-in display should be forced to
+         black in software (to avoid aliasing or emulate a cutout that is not physically existent).
+         -->
+    <bool name="config_fillMainBuiltInDisplayCutout">false</bool>
+
     <!-- Ultrasound support for Mic/speaker path -->
     <!-- Whether the default microphone audio source supports near-ultrasound frequencies
          (range of 18 - 21 kHz). -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6c1661c..2c824ea0 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -152,11 +152,11 @@
     <dimen name="dialog_padding">16dp</dimen>
 
     <!-- The margin on the start of the content view -->
-    <dimen name="notification_content_margin_start">24dp</dimen>
+    <dimen name="notification_content_margin_start">16dp</dimen>
 
     <!-- The margin on the end of the content view
         Keep in sync with notification_content_plus_picture_margin! -->
-    <dimen name="notification_content_margin_end">24dp</dimen>
+    <dimen name="notification_content_margin_end">16dp</dimen>
 
     <!-- The margin on the end of the content view with a picture.
         Keep in sync with notification_content_plus_picture_margin! -->
@@ -166,7 +166,7 @@
         content end margin.
         Keep equal to (notification_content_picture_margin + notification_content_margin_end)!
     -->
-    <dimen name="notification_content_plus_picture_margin_end">80dp</dimen>
+    <dimen name="notification_content_plus_picture_margin_end">72dp</dimen>
 
     <!-- The additional margin on the sides of the ambient view. -->
     <dimen name="notification_extra_margin_ambient">16dp</dimen>
@@ -175,10 +175,10 @@
     <dimen name="notification_action_list_height">56dp</dimen>
 
     <!-- height of the content margin to accomodate for the header -->
-    <dimen name="notification_content_margin_top">41.5dp</dimen>
+    <dimen name="notification_content_margin_top">46dp</dimen>
 
     <!-- height of the content margin on the bottom -->
-    <dimen name="notification_content_margin_bottom">18dp</dimen>
+    <dimen name="notification_content_margin_bottom">20dp</dimen>
 
     <!-- The height of the progress bar. -->
     <dimen name="notification_progress_bar_height">15dp</dimen>
@@ -187,19 +187,19 @@
     <dimen name="notification_progress_margin_top">8dp</dimen>
 
     <!-- height of the notification header (for icon and package name) -->
-    <dimen name="notification_header_height">54dp</dimen>
+    <dimen name="notification_header_height">50dp</dimen>
 
     <!-- The height of the background for a notification header on a group -->
     <dimen name="notification_header_background_height">49.5dp</dimen>
 
     <!-- The top padding for the notification header -->
-    <dimen name="notification_header_padding_top">14dp</dimen>
+    <dimen name="notification_header_padding_top">16dp</dimen>
 
     <!-- The bottom padding for the notification header -->
-    <dimen name="notification_header_padding_bottom">13dp</dimen>
+    <dimen name="notification_header_padding_bottom">16dp</dimen>
 
     <!-- The margin at the bottom of the notification header. -->
-    <dimen name="notification_header_margin_bottom">5dp</dimen>
+    <dimen name="notification_header_margin_bottom">0dp</dimen>
 
     <!-- The end margin after the application icon in the notification header -->
     <dimen name="notification_header_icon_margin_end">3dp</dimen>
@@ -250,7 +250,7 @@
     <dimen name="media_notification_expanded_image_margin_bottom">20dp</dimen>
 
     <!-- The absolute height for the header in a media notification. -->
-    <dimen name="media_notification_header_height">53dp</dimen>
+    <dimen name="media_notification_header_height">@dimen/notification_header_height</dimen>
 
     <!-- The margin of the content to an image-->
     <dimen name="notification_content_image_margin_end">8dp</dimen>
@@ -590,7 +590,7 @@
     <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
     <dimen name="notification_media_image_max_width">280dp</dimen>
     <!-- The size of the right icon -->
-    <dimen name="notification_right_icon_size">40dp</dimen>
+    <dimen name="notification_right_icon_size">38dp</dimen>
 
     <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->
     <dimen name="notification_custom_view_max_image_height_low_ram">208dp</dimen>
@@ -607,7 +607,7 @@
     <!-- The size of the right icon image when on low ram -->
     <dimen name="notification_right_icon_size_low_ram">40dp</dimen>
 
-    <dimen name="messaging_avatar_size">24dp</dimen>
+    <dimen name="messaging_avatar_size">@dimen/notification_right_icon_size</dimen>
 
     <!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
     <dimen name="autofill_dataset_picker_max_size">90%</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6ec88dc..58ae76c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2861,6 +2861,7 @@
       <public name="widgetFeatures" />
       <public name="appComponentFactory" />
       <public name="fallbackLineSpacing" />
+      <public name="accessibilityPaneTitle" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0618a82..b2fa294 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -484,6 +484,9 @@
     <!-- label for item that logouts the current user -->
     <string name="global_action_logout">End session</string>
 
+    <!-- label for screenshot item in power menu -->
+    <string name="global_action_screenshot">Screenshot</string>
+
     <!-- Take bug report menu title [CHAR LIMIT=NONE] -->
     <string name="bugreport_title">Take bug report</string>
     <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
@@ -3030,6 +3033,10 @@
     <string name="wifi_wakeup_onboarding_subtext">When you\'re near a high quality saved network</string>
     <!--Notification action to disable Wi-Fi Wake during onboarding.-->
     <string name="wifi_wakeup_onboarding_action_disable">Don\'t turn back on</string>
+    <!--Notification title for when Wi-Fi Wake enables Wi-Fi.-->
+    <string name="wifi_wakeup_enabled_title">Wi\u2011Fi turned on automatically</string>
+    <!--Notification content for when Wi-Fi Wake enables Wi-Fi. %1$s is the SSID of the nearby saved network that triggered the wakeup. -->
+    <string name="wifi_wakeup_enabled_content">You\u0027re near a saved network: <xliff:g id="network_ssid">%1$s</xliff:g></string>
 
     <!-- A notification is shown when a wifi captive portal network is detected.  This is the notification's title. -->
     <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
@@ -4795,4 +4802,11 @@
 
     <!--Battery saver warning. STOPSHIP: Remove it eventually. -->
     <string name="battery_saver_warning_title" translatable="false">Extreme battery saver</string>
+
+    <!-- Label for the uninstall button on the harmful app warning dialog. -->
+    <string name="harmful_app_warning_uninstall">Uninstall</string>
+    <!-- Label for the launch anyway button on the harmful app warning dialog. -->
+    <string name="harmful_app_warning_launch_anyway">Launch anyway</string>
+    <!-- Title for the harmful app warning dialog. -->
+    <string name="harmful_app_warning_title">Uninstall harmful app?</string>
 </resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index def650a..fa3cf2f 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -502,20 +502,17 @@
     <style name="Widget.Material.Notification.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" />
 
     <style name="Widget.Material.Notification.MessagingText" parent="Widget.Material.Light.TextView">
-        <item name="layout_width">match_parent</item>
+        <item name="layout_width">wrap_content</item>
         <item name="layout_height">wrap_content</item>
         <item name="ellipsize">end</item>
         <item name="textAppearance">@style/TextAppearance.Material.Notification</item>
-        <item name="background">@drawable/messaging_message_background</item>
     </style>
 
     <style name="Widget.Material.Notification.MessagingName" parent="Widget.Material.Light.TextView">
         <item name="layout_width">wrap_content</item>
         <item name="layout_height">wrap_content</item>
         <item name="ellipsize">end</item>
-        <item name="textAppearance">@style/TextAppearance.Material.Notification</item>
-        <item name="textColor">@color/notification_primary_text_color_light</item>
-        <item name="textSize">12sp</item>
+        <item name="textAppearance">@style/TextAppearance.Material.Notification.Title</item>
     </style>
 
     <!-- Widget Styles -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 22a4251..f4ced58 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -462,6 +462,7 @@
   <java-symbol type="bool" name="config_useDefaultFocusHighlight" />
   <java-symbol type="array" name="config_deviceSpecificSystemServices" />
   <java-symbol type="string" name="config_deviceSpecificDevicePolicyManagerService" />
+  <java-symbol type="integer" name="config_num_physical_slots" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
@@ -1721,6 +1722,7 @@
   <java-symbol type="string" name="global_action_lockdown" />
   <java-symbol type="string" name="global_action_voice_assist" />
   <java-symbol type="string" name="global_action_assist" />
+  <java-symbol type="string" name="global_action_screenshot" />
   <java-symbol type="string" name="invalidPuk" />
   <java-symbol type="string" name="lockscreen_carrier_default" />
   <java-symbol type="style" name="Animation.LockScreen" />
@@ -1815,7 +1817,7 @@
   <java-symbol type="bool" name="config_wimaxEnabled" />
   <java-symbol type="bool" name="show_ongoing_ime_switcher" />
   <java-symbol type="color" name="config_defaultNotificationColor" />
-  <java-symbol type="color" name="input_method_navigation_guard" />
+  <java-symbol type="color" name="decor_view_status_guard" />
   <java-symbol type="drawable" name="ic_notification_ime_default" />
   <java-symbol type="drawable" name="ic_menu_refresh" />
   <java-symbol type="drawable" name="ic_settings" />
@@ -1918,6 +1920,8 @@
   <java-symbol type="string" name="wifi_wakeup_onboarding_title" />
   <java-symbol type="string" name="wifi_wakeup_onboarding_subtext" />
   <java-symbol type="string" name="wifi_wakeup_onboarding_action_disable" />
+  <java-symbol type="string" name="wifi_wakeup_enabled_title" />
+  <java-symbol type="string" name="wifi_wakeup_enabled_content" />
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
@@ -2434,9 +2438,6 @@
   <!-- Cascading submenus -->
   <java-symbol type="dimen" name="cascading_menus_min_smallest_width" />
 
-  <!-- From SignalStrength -->
-  <java-symbol type="array" name="config_lteDbmThresholds" />
-
   <java-symbol type="string" name="android_system_label" />
   <java-symbol type="string" name="system_error_wipe_data" />
   <java-symbol type="string" name="system_error_manufacturer" />
@@ -2608,10 +2609,12 @@
   <java-symbol type="string" name="notification_hidden_text" />
   <java-symbol type="id" name="app_name_text" />
   <java-symbol type="id" name="header_text" />
+  <java-symbol type="id" name="header_text_secondary" />
   <java-symbol type="id" name="expand_button" />
   <java-symbol type="id" name="notification_header" />
   <java-symbol type="id" name="time_divider" />
   <java-symbol type="id" name="header_text_divider" />
+  <java-symbol type="id" name="header_text_secondary_divider" />
   <java-symbol type="id" name="text_line_1" />
   <java-symbol type="drawable" name="ic_expand_notification" />
   <java-symbol type="drawable" name="ic_collapse_notification" />
@@ -2887,8 +2890,9 @@
 
   <java-symbol type="bool" name="config_permissionReviewRequired" />
 
-
+  <!-- Global actions icons -->
   <java-symbol type="drawable" name="ic_restart" />
+  <java-symbol type="drawable" name="ic_screenshot" />
 
   <java-symbol type="drawable" name="emergency_icon" />
 
@@ -3198,6 +3202,8 @@
   <java-symbol type="string" name="battery_saver_warning_title" />
 
   <java-symbol type="string" name="global_action_logout" />
+  <java-symbol type="string" name="config_mainBuiltInDisplayCutout" />
+  <java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" />
   <java-symbol type="drawable" name="ic_logout" />
 
   <java-symbol type="array" name="config_autoBrightnessDisplayValuesNits" />
@@ -3205,4 +3211,8 @@
   <java-symbol type="array" name="config_screenBrightnessNits" />
 
   <java-symbol type="string" name="shortcut_disabled_reason_unknown" />
+
+  <java-symbol type="string" name="harmful_app_warning_uninstall" />
+  <java-symbol type="string" name="harmful_app_warning_launch_anyway" />
+  <java-symbol type="string" name="harmful_app_warning_title" />
 </resources>
diff --git a/core/tests/coretests/res/layout/activity_text_view.xml b/core/tests/coretests/res/layout/activity_text_view.xml
index e795c10..dca1656 100644
--- a/core/tests/coretests/res/layout/activity_text_view.xml
+++ b/core/tests/coretests/res/layout/activity_text_view.xml
@@ -25,4 +25,9 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
 
+    <TextView
+        android:id="@+id/nonselectable_textview"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
 </LinearLayout>
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index b51c677..9ab7544 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -18,11 +18,13 @@
 
 import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.BitmapFactory;
@@ -40,6 +42,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.function.Consumer;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NotificationTest {
@@ -281,6 +285,40 @@
         assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION));
     }
 
+    @Test
+    public void action_builder_hasDefault() {
+        Notification.Action action = makeNotificationAction(null);
+        assertEquals(Notification.Action.SEMANTIC_ACTION_NONE, action.getSemanticAction());
+    }
+
+    @Test
+    public void action_builder_setSemanticAction() {
+        Notification.Action action = makeNotificationAction(
+                builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_REPLY));
+        assertEquals(Notification.Action.SEMANTIC_ACTION_REPLY, action.getSemanticAction());
+    }
+
+    @Test
+    public void action_parcel() {
+        Notification.Action action = writeAndReadParcelable(
+                makeNotificationAction(builder -> {
+                    builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_ARCHIVE);
+                    builder.setAllowGeneratedReplies(true);
+                }));
+
+        assertEquals(Notification.Action.SEMANTIC_ACTION_ARCHIVE, action.getSemanticAction());
+        assertTrue(action.getAllowGeneratedReplies());
+    }
+
+    @Test
+    public void action_clone() {
+        Notification.Action action = makeNotificationAction(
+                builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_DELETE));
+        assertEquals(
+                Notification.Action.SEMANTIC_ACTION_DELETE,
+                action.clone().getSemanticAction());
+    }
+
     private Notification.Builder getMediaNotification() {
         MediaSession session = new MediaSession(mContext, "test");
         return new Notification.Builder(mContext, "color")
@@ -300,4 +338,18 @@
         p.setDataPosition(0);
         return p.readParcelable(/* classLoader */ null);
     }
+
+    /**
+     * Creates a Notification.Action by mocking initial dependencies and then applying
+     * transformations if they're defined.
+     */
+    private Notification.Action makeNotificationAction(
+            @Nullable Consumer<Notification.Action.Builder> transformation) {
+        Notification.Action.Builder actionBuilder =
+                new Notification.Action.Builder(null, "Test Title", null);
+        if (transformation != null) {
+            transformation.accept(actionBuilder);
+        }
+        return actionBuilder.build();
+    }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index c19a343..aefc47e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -42,8 +42,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-// TODO: b/70616950
-//@Presubmit
+@Presubmit
 public class ObjectPoolTests {
 
     // 1. Check if two obtained objects from pool are not the same.
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 53f4f3a..267267e 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -146,14 +146,14 @@
     }
 
     private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
-            boolean isPlatformReleased, int expectedTargetSdk) {
+            boolean isPlatformReleased, int expectedTargetSdk, boolean forceCurrentDev) {
         final String[] outError = new String[1];
         final int result = PackageParser.computeTargetSdkVersion(
                 targetSdkVersion,
                 targetSdkCodename,
-                PLATFORM_VERSION,
                 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
-                outError);
+                outError,
+                forceCurrentDev);
 
         assertEquals(result, expectedTargetSdk);
 
@@ -169,34 +169,45 @@
         // Do allow older release targetSdkVersion on pre-release platform.
         // APP: Released API 10
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION,
+                false /* forceCurrentDev */);
 
         // Do allow same release targetSdkVersion on pre-release platform.
         // APP: Released API 20
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION,
+                false /* forceCurrentDev */);
 
         // Do allow newer release targetSdkVersion on pre-release platform.
         // APP: Released API 30
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION,
+                false /* forceCurrentDev */);
 
         // Don't allow older pre-release targetSdkVersion on pre-release platform.
         // APP: Pre-release API 10
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1,
+                false /* forceCurrentDev */);
 
         // Do allow same pre-release targetSdkVersion on pre-release platform,
         // but overwrite the specified version with CUR_DEVELOPMENT.
         // APP: Pre-release API 20
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
-                Build.VERSION_CODES.CUR_DEVELOPMENT);
+                Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
 
         // Don't allow newer pre-release targetSdkVersion on pre-release platform.
         // APP: Pre-release API 30
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1,
+                false /* forceCurrentDev */);
+
+        // Force newer pre-release targetSdkVersion to current pre-release platform.
+        // APP: Pre-release API 30
+        // DEV: Pre-release API 20
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
+                Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
     }
 
     @Test
@@ -204,32 +215,38 @@
         // Do allow older release targetSdkVersion on released platform.
         // APP: Released API 10
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION,
+                false /* forceCurrentDev */);
 
         // Do allow same release targetSdkVersion on released platform.
         // APP: Released API 20
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION,
+                false /* forceCurrentDev */);
 
         // Do allow newer release targetSdkVersion on released platform.
         // APP: Released API 30
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION,
+                false /* forceCurrentDev */);
 
         // Don't allow older pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 10
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1,
+                false /* forceCurrentDev */);
 
         // Don't allow same pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 20
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1,
+                false /* forceCurrentDev */);
 
         // Don't allow newer pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 30
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1,
+                false /* forceCurrentDev */);
     }
 
     /**
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 7cfedc8..410bee0 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -211,6 +211,7 @@
                     Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
                     Settings.Global.FANCY_IME_ANIMATIONS,
                     Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
+                    Settings.Global.FORCED_APP_STANDBY_ENABLED,
                     Settings.Global.FSTRIM_MANDATORY_INTERVAL,
                     Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
                     Settings.Global.GLOBAL_HTTP_PROXY_HOST,
@@ -349,6 +350,7 @@
                     Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
                     Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
                     Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
+                    Settings.Global.SYS_VDSO,
                     Settings.Global.TCP_DEFAULT_INIT_RWND,
                     Settings.Global.TETHER_DUN_APN,
                     Settings.Global.TETHER_DUN_REQUIRED,
@@ -420,7 +422,8 @@
                     Settings.Global.WTF_IS_FATAL,
                     Settings.Global.ZEN_MODE,
                     Settings.Global.ZEN_MODE_CONFIG_ETAG,
-                    Settings.Global.ZEN_MODE_RINGER_LEVEL);
+                    Settings.Global.ZEN_MODE_RINGER_LEVEL,
+                    Settings.Global.ZRAM_ENABLED);
 
     private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
              newHashSet(
@@ -512,6 +515,7 @@
                  Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
                  Settings.Secure.SETTINGS_CLASSNAME,
                  Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, // candidate?
+                 Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
                  Settings.Secure.SKIP_FIRST_USE_HINTS, // candidate?
                  Settings.Secure.SMS_DEFAULT_APPLICATION,
                  Settings.Secure.TRUST_AGENTS_INITIALIZED,
diff --git a/core/tests/coretests/src/android/text/MeasuredTextTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
similarity index 87%
rename from core/tests/coretests/src/android/text/MeasuredTextTest.java
rename to core/tests/coretests/src/android/text/MeasuredParagraphTest.java
index ddef0c6..5d33397 100644
--- a/core/tests/coretests/src/android/text/MeasuredTextTest.java
+++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
@@ -31,7 +31,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class MeasuredTextTest {
+public class MeasuredParagraphTest {
     private static final TextDirectionHeuristic LTR = TextDirectionHeuristics.LTR;
     private static final TextDirectionHeuristic RTL = TextDirectionHeuristics.RTL;
 
@@ -60,9 +60,9 @@
 
     @Test
     public void buildForBidi() {
-        MeasuredText mt = null;
+        MeasuredParagraph mt = null;
 
-        mt = MeasuredText.buildForBidi("XXX", 0, 3, LTR, null);
+        mt = MeasuredParagraph.buildForBidi("XXX", 0, 3, LTR, null);
         assertNotNull(mt);
         assertNotNull(mt.getChars());
         assertEquals("XXX", charsToString(mt.getChars()));
@@ -75,7 +75,7 @@
         assertEquals(0, mt.getNativePtr());
 
         // Recycle it
-        MeasuredText mt2 = MeasuredText.buildForBidi("_VVV_", 1, 4, RTL, mt);
+        MeasuredParagraph mt2 = MeasuredParagraph.buildForBidi("_VVV_", 1, 4, RTL, mt);
         assertEquals(mt2, mt);
         assertNotNull(mt2.getChars());
         assertEquals("VVV", charsToString(mt.getChars()));
@@ -91,9 +91,9 @@
 
     @Test
     public void buildForMeasurement() {
-        MeasuredText mt = null;
+        MeasuredParagraph mt = null;
 
-        mt = MeasuredText.buildForMeasurement(PAINT, "XXX", 0, 3, LTR, null);
+        mt = MeasuredParagraph.buildForMeasurement(PAINT, "XXX", 0, 3, LTR, null);
         assertNotNull(mt);
         assertNotNull(mt.getChars());
         assertEquals("XXX", charsToString(mt.getChars()));
@@ -109,7 +109,8 @@
         assertEquals(0, mt.getNativePtr());
 
         // Recycle it
-        MeasuredText mt2 = MeasuredText.buildForMeasurement(PAINT, "_VVV_", 1, 4, RTL, mt);
+        MeasuredParagraph mt2 =
+                MeasuredParagraph.buildForMeasurement(PAINT, "_VVV_", 1, 4, RTL, mt);
         assertEquals(mt2, mt);
         assertNotNull(mt2.getChars());
         assertEquals("VVV", charsToString(mt.getChars()));
@@ -129,9 +130,9 @@
 
     @Test
     public void buildForStaticLayout() {
-        MeasuredText mt = null;
+        MeasuredParagraph mt = null;
 
-        mt = MeasuredText.buildForStaticLayout(PAINT, "XXX", 0, 3, LTR, null);
+        mt = MeasuredParagraph.buildForStaticLayout(PAINT, "XXX", 0, 3, LTR, null);
         assertNotNull(mt);
         assertNotNull(mt.getChars());
         assertEquals("XXX", charsToString(mt.getChars()));
@@ -145,7 +146,8 @@
         assertNotEquals(0, mt.getNativePtr());
 
         // Recycle it
-        MeasuredText mt2 = MeasuredText.buildForStaticLayout(PAINT, "_VVV_", 1, 4, RTL, mt);
+        MeasuredParagraph mt2 =
+                MeasuredParagraph.buildForStaticLayout(PAINT, "_VVV_", 1, 4, RTL, mt);
         assertEquals(mt2, mt);
         assertNotNull(mt2.getChars());
         assertEquals("VVV", charsToString(mt.getChars()));
@@ -163,6 +165,6 @@
 
     @Test
     public void testFor70146381() {
-        MeasuredText.buildForMeasurement(PAINT, "X…", 0, 2, RTL, null);
+        MeasuredParagraph.buildForMeasurement(PAINT, "X…", 0, 2, RTL, null);
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
new file mode 100644
index 0000000..9ee7fac
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.os.LocaleList;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextClassificationTest {
+
+    public BitmapDrawable generateTestDrawable(int width, int height, int colorValue) {
+        final int numPixels = width * height;
+        final int[] colors = new int[numPixels];
+        for (int i = 0; i < numPixels; ++i) {
+            colors[i] = colorValue;
+        }
+        final Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
+        final BitmapDrawable drawable = new BitmapDrawable(null, bitmap);
+        drawable.setTargetDensity(bitmap.getDensity());
+        return drawable;
+    }
+
+    @Test
+    public void testParcel() {
+        final String text = "text";
+        final BitmapDrawable primaryIcon = generateTestDrawable(16, 16, Color.RED);
+        final String primaryLabel = "primarylabel";
+        final Intent primaryIntent = new Intent("primaryintentaction");
+        final View.OnClickListener primaryOnClick = v -> { };
+        final BitmapDrawable secondaryIcon0 = generateTestDrawable(32, 288, Color.GREEN);
+        final String secondaryLabel0 = "secondarylabel0";
+        final Intent secondaryIntent0 = new Intent("secondaryintentaction0");
+        final BitmapDrawable secondaryIcon1 = generateTestDrawable(576, 288, Color.BLUE);
+        final String secondaryLabel1 = "secondaryLabel1";
+        final Intent secondaryIntent1 = null;
+        final BitmapDrawable secondaryIcon2 = null;
+        final String secondaryLabel2 = null;
+        final Intent secondaryIntent2 = new Intent("secondaryintentaction2");
+        final ColorDrawable secondaryIcon3 = new ColorDrawable(Color.CYAN);
+        final String secondaryLabel3 = null;
+        final Intent secondaryIntent3 = null;
+        final String signature = "signature";
+        final TextClassification reference = new TextClassification.Builder()
+                .setText(text)
+                .setPrimaryAction(primaryIntent, primaryLabel, primaryIcon)
+                .setOnClickListener(primaryOnClick)
+                .addSecondaryAction(null, null, null)  // ignored
+                .addSecondaryAction(secondaryIntent0, secondaryLabel0, secondaryIcon0)
+                .addSecondaryAction(secondaryIntent1, secondaryLabel1, secondaryIcon1)
+                .addSecondaryAction(secondaryIntent2, secondaryLabel2, secondaryIcon2)
+                .addSecondaryAction(secondaryIntent3, secondaryLabel3, secondaryIcon3)
+                .setEntityType(TextClassifier.TYPE_ADDRESS, 0.3f)
+                .setEntityType(TextClassifier.TYPE_PHONE, 0.7f)
+                .setSignature(signature)
+                .build();
+
+        // Parcel and unparcel using ParcelableWrapper.
+        final TextClassification.ParcelableWrapper parcelableReference = new TextClassification
+                .ParcelableWrapper(reference);
+        final Parcel parcel = Parcel.obtain();
+        parcelableReference.writeToParcel(parcel, parcelableReference.describeContents());
+        parcel.setDataPosition(0);
+        final TextClassification result =
+                TextClassification.ParcelableWrapper.CREATOR.createFromParcel(
+                        parcel).getTextClassification();
+
+        assertEquals(text, result.getText());
+        assertEquals(signature, result.getSignature());
+        assertEquals(4, result.getSecondaryActionsCount());
+
+        // Primary action (re-use existing icon).
+        final Bitmap resPrimaryIcon = ((BitmapDrawable) result.getIcon()).getBitmap();
+        assertEquals(primaryIcon.getBitmap().getPixel(0, 0), resPrimaryIcon.getPixel(0, 0));
+        assertEquals(16, resPrimaryIcon.getWidth());
+        assertEquals(16, resPrimaryIcon.getHeight());
+        assertEquals(primaryLabel, result.getLabel());
+        assertEquals(primaryIntent.getAction(), result.getIntent().getAction());
+        assertEquals(null, result.getOnClickListener());  // Non-parcelable.
+
+        // Secondary action 0 (scale with  height limit).
+        final Bitmap resSecondaryIcon0 = ((BitmapDrawable) result.getSecondaryIcon(0)).getBitmap();
+        assertEquals(secondaryIcon0.getBitmap().getPixel(0, 0), resSecondaryIcon0.getPixel(0, 0));
+        assertEquals(16, resSecondaryIcon0.getWidth());
+        assertEquals(144, resSecondaryIcon0.getHeight());
+        assertEquals(secondaryLabel0, result.getSecondaryLabel(0));
+        assertEquals(secondaryIntent0.getAction(), result.getSecondaryIntent(0).getAction());
+
+        // Secondary action 1 (scale with width limit).
+        final Bitmap resSecondaryIcon1 = ((BitmapDrawable) result.getSecondaryIcon(1)).getBitmap();
+        assertEquals(secondaryIcon1.getBitmap().getPixel(0, 0), resSecondaryIcon1.getPixel(0, 0));
+        assertEquals(144, resSecondaryIcon1.getWidth());
+        assertEquals(72, resSecondaryIcon1.getHeight());
+        assertEquals(secondaryLabel1, result.getSecondaryLabel(1));
+        assertEquals(null, result.getSecondaryIntent(1));
+
+        // Secondary action 2 (no icon).
+        assertEquals(null, result.getSecondaryIcon(2));
+        assertEquals(null, result.getSecondaryLabel(2));
+        assertEquals(secondaryIntent2.getAction(), result.getSecondaryIntent(2).getAction());
+
+        // Secondary action 3 (convert non-bitmap drawable with negative size).
+        final Bitmap resSecondaryIcon3 = ((BitmapDrawable) result.getSecondaryIcon(3)).getBitmap();
+        assertEquals(secondaryIcon3.getColor(), resSecondaryIcon3.getPixel(0, 0));
+        assertEquals(1, resSecondaryIcon3.getWidth());
+        assertEquals(1, resSecondaryIcon3.getHeight());
+        assertEquals(null, result.getSecondaryLabel(3));
+        assertEquals(null, result.getSecondaryIntent(3));
+
+        // Entities.
+        assertEquals(2, result.getEntityCount());
+        assertEquals(TextClassifier.TYPE_PHONE, result.getEntity(0));
+        assertEquals(TextClassifier.TYPE_ADDRESS, result.getEntity(1));
+        assertEquals(0.7f, result.getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f);
+        assertEquals(0.3f, result.getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f);
+    }
+
+    @Test
+    public void testParcelOptions() {
+        TextClassification.Options reference = new TextClassification.Options();
+        reference.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY));
+
+        // Parcel and unparcel.
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        TextClassification.Options result = TextClassification.Options.CREATOR.createFromParcel(
+                parcel);
+
+        assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
new file mode 100644
index 0000000..a82542c
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.LocaleList;
+import android.os.Parcel;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArrayMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextLinksTest {
+
+    private TextClassificationManager mTcm;
+    private TextClassifier mClassifier;
+
+    @Before
+    public void setup() {
+        mTcm = InstrumentationRegistry.getTargetContext()
+                .getSystemService(TextClassificationManager.class);
+        mTcm.setTextClassifier(null);
+        mClassifier = mTcm.getTextClassifier();
+    }
+
+    private Map<String, Float> getEntityScores(float address, float phone, float other) {
+        final Map<String, Float> result = new ArrayMap<>();
+        if (address > 0.f) {
+            result.put(TextClassifier.TYPE_ADDRESS, address);
+        }
+        if (phone > 0.f) {
+            result.put(TextClassifier.TYPE_PHONE, phone);
+        }
+        if (other > 0.f) {
+            result.put(TextClassifier.TYPE_OTHER, other);
+        }
+        return result;
+    }
+
+    @Test
+    public void testParcel() {
+        final String fullText = "this is just a test";
+        final TextLinks reference = new TextLinks.Builder(fullText)
+                .addLink(new TextLinks.TextLink(fullText, 0, 4, getEntityScores(0.f, 0.f, 1.f)))
+                .addLink(new TextLinks.TextLink(fullText, 5, 12, getEntityScores(.8f, .1f, .5f)))
+                .build();
+
+        // Parcel and unparcel.
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        final TextLinks result = TextLinks.CREATOR.createFromParcel(parcel);
+        final List<TextLinks.TextLink> resultList = new ArrayList<>(result.getLinks());
+
+        assertEquals(2, resultList.size());
+        assertEquals(0, resultList.get(0).getStart());
+        assertEquals(4, resultList.get(0).getEnd());
+        assertEquals(1, resultList.get(0).getEntityCount());
+        assertEquals(TextClassifier.TYPE_OTHER, resultList.get(0).getEntity(0));
+        assertEquals(1.f, resultList.get(0).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f);
+        assertEquals(5, resultList.get(1).getStart());
+        assertEquals(12, resultList.get(1).getEnd());
+        assertEquals(3, resultList.get(1).getEntityCount());
+        assertEquals(TextClassifier.TYPE_ADDRESS, resultList.get(1).getEntity(0));
+        assertEquals(TextClassifier.TYPE_OTHER, resultList.get(1).getEntity(1));
+        assertEquals(TextClassifier.TYPE_PHONE, resultList.get(1).getEntity(2));
+        assertEquals(.8f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f);
+        assertEquals(.5f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f);
+        assertEquals(.1f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f);
+    }
+
+    @Test
+    public void testParcelOptions() {
+        TextClassifier.EntityConfig entityConfig = new TextClassifier.EntityConfig(
+                TextClassifier.ENTITY_PRESET_NONE);
+        entityConfig.includeEntities("a", "b", "c");
+        entityConfig.excludeEntities("b");
+        TextLinks.Options reference = new TextLinks.Options();
+        reference.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY));
+        reference.setEntityConfig(entityConfig);
+
+        // Parcel and unparcel.
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        TextLinks.Options result = TextLinks.Options.CREATOR.createFromParcel(parcel);
+
+        assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
+        assertEquals(Arrays.asList("a", "c"), result.getEntityConfig().getEntities(mClassifier));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
new file mode 100644
index 0000000..e920236
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.LocaleList;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextSelectionTest {
+
+    @Test
+    public void testParcel() {
+        final int startIndex = 13;
+        final int endIndex = 37;
+        final String signature = "signature";
+        final TextSelection reference = new TextSelection.Builder(startIndex, endIndex)
+                .setEntityType(TextClassifier.TYPE_ADDRESS, 0.3f)
+                .setEntityType(TextClassifier.TYPE_PHONE, 0.7f)
+                .setEntityType(TextClassifier.TYPE_URL, 0.1f)
+                .setSignature(signature)
+                .build();
+
+        // Parcel and unparcel using ParcelableWrapper.
+        final TextSelection.ParcelableWrapper parcelableReference = new TextSelection
+                .ParcelableWrapper(reference);
+        final Parcel parcel = Parcel.obtain();
+        parcelableReference.writeToParcel(parcel, parcelableReference.describeContents());
+        parcel.setDataPosition(0);
+        final TextSelection result =
+                TextSelection.ParcelableWrapper.CREATOR.createFromParcel(
+                        parcel).getTextSelection();
+
+        assertEquals(startIndex, result.getSelectionStartIndex());
+        assertEquals(endIndex, result.getSelectionEndIndex());
+        assertEquals(signature, result.getSignature());
+
+        assertEquals(3, result.getEntityCount());
+        assertEquals(TextClassifier.TYPE_PHONE, result.getEntity(0));
+        assertEquals(TextClassifier.TYPE_ADDRESS, result.getEntity(1));
+        assertEquals(TextClassifier.TYPE_URL, result.getEntity(2));
+        assertEquals(0.7f, result.getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f);
+        assertEquals(0.3f, result.getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f);
+        assertEquals(0.1f, result.getConfidenceScore(TextClassifier.TYPE_URL), 1e-7f);
+    }
+
+    @Test
+    public void testParcelOptions() {
+        TextSelection.Options reference = new TextSelection.Options();
+        reference.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY));
+        reference.setDarkLaunchAllowed(true);
+
+        // Parcel and unparcel.
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        TextSelection.Options result = TextSelection.Options.CREATOR.createFromParcel(parcel);
+
+        assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
+        assertTrue(result.isDarkLaunchAllowed());
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 1a654f4..bbca12f 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -311,11 +311,20 @@
 
     @Test
     public void testToolbarAppearsAfterLinkClicked() throws Throwable {
+        runToolbarAppearsAfterLinkClickedTest(R.id.textview);
+    }
+
+    @Test
+    public void testToolbarAppearsAfterLinkClickedNonselectable() throws Throwable {
+        runToolbarAppearsAfterLinkClickedTest(R.id.nonselectable_textview);
+    }
+
+    private void runToolbarAppearsAfterLinkClickedTest(int id) throws Throwable {
+        TextView textView = mActivity.findViewById(id);
         useSystemDefaultTextClassifier();
         TextClassificationManager textClassificationManager =
                 mActivity.getSystemService(TextClassificationManager.class);
         TextClassifier textClassifier = textClassificationManager.getTextClassifier();
-        final TextView textView = mActivity.findViewById(R.id.textview);
         SpannableString content = new SpannableString("Call me at +19148277737");
         TextLinks links = textClassifier.generateLinks(content);
         links.apply(content, null);
@@ -331,7 +340,7 @@
 
         TextLinks.TextLink textLink = links.getLinks().iterator().next();
         int position = (textLink.getStart() + textLink.getEnd()) / 2;
-        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(position));
+        onView(withId(id)).perform(clickOnTextAtIndex(position));
         sleepForFloatingToolbarPopup();
         assertFloatingToolbarIsDisplayed();
     }
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index d2c855b..f169f22 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -168,6 +168,8 @@
     <assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
     <assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />
 
+    <assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
+
     <!-- This is a list of all the libraries available for application
          code to link against. -->
 
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 94b219a..419e2b7 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -239,7 +239,7 @@
     };
 
     /**
-     *  Supplied to onException if the provided data is incomplete.
+     *  Supplied to onPartialImage if the provided data is incomplete.
      *
      *  Will never be thrown by ImageDecoder.
      *
@@ -252,7 +252,7 @@
      *
      *  May be thrown if there is nothing to display.
      *
-     *  If supplied to onException, there may be a correct partial image to
+     *  If supplied to onPartialImage, there may be a correct partial image to
      *  display.
      */
     public static class CorruptException extends IOException {};
@@ -275,17 +275,21 @@
     /**
      *  Optional listener supplied to the ImageDecoder.
      */
-    public static interface OnExceptionListener {
+    public static interface OnPartialImageListener {
         /**
-         *  Called when there is a problem in the stream or in the data.
-         *  FIXME: Report how much of the image has been decoded?
+         *  Called when there is only a partial image to display.
          *
-         *  @param e IOException containing information about the error.
-         *  @return True to create and return a {@link Drawable}/
-         *      {@link Bitmap} with partial data. False to return
-         *      {@code null}. True is the default.
+         *  If the input is incomplete or contains an error, this listener lets
+         *  the client know that and allows them to optionally bypass the rest
+         *  of the decode/creation process.
+         *
+         *  @param e IOException containing information about the error that
+         *      interrupted the decode.
+         *  @return True (which is the default) to create and return a
+         *      {@link Drawable}/{@link Bitmap} with partial data. False to
+         *      abort the decode and throw the {@link java.io.IOException}.
          */
-        public boolean onException(IOException e);
+        public boolean onPartialImage(IOException e);
     };
 
     // Fields
@@ -302,8 +306,8 @@
     private boolean mAsAlphaMask = false;
     private Rect    mCropRect;
 
-    private PostProcess         mPostProcess;
-    private OnExceptionListener mOnExceptionListener;
+    private PostProcess            mPostProcess;
+    private OnPartialImageListener mOnPartialImageListener;
 
     // Objects for interacting with the input.
     private InputStream         mInputStream;
@@ -557,13 +561,13 @@
     }
 
     /**
-     *  Set (replace) the {@link OnExceptionListener} on this object.
+     *  Set (replace) the {@link OnPartialImageListener} on this object.
      *
      *  Will be called if there is an error in the input. Without one, a
      *  partial {@link Bitmap} will be created.
      */
-    public void setOnExceptionListener(OnExceptionListener l) {
-        mOnExceptionListener = l;
+    public void setOnPartialImageListener(OnPartialImageListener l) {
+        mOnPartialImageListener = l;
     }
 
     /**
@@ -712,7 +716,7 @@
             }
 
             Bitmap bm = nDecodeBitmap(decoder.mNativePtr,
-                                      decoder.mOnExceptionListener,
+                                      decoder.mOnPartialImageListener,
                                       decoder.mPostProcess,
                                       decoder.mDesiredWidth,
                                       decoder.mDesiredHeight,
@@ -722,13 +726,6 @@
                                       false,    // mRequireUnpremultiplied
                                       decoder.mPreferRamOverQuality,
                                       decoder.mAsAlphaMask);
-            if (bm == null) {
-                // FIXME: bm should never be null. Currently a return value
-                // of false from onException will result in bm being null. What
-                // is the right API to choose to discard partial Bitmaps?
-                return null;
-            }
-
             Resources res = src.getResources();
             if (res == null) {
                 bm.setDensity(Bitmap.DENSITY_NONE);
@@ -786,7 +783,7 @@
             decoder.checkState();
 
             return nDecodeBitmap(decoder.mNativePtr,
-                                 decoder.mOnExceptionListener,
+                                 decoder.mOnPartialImageListener,
                                  decoder.mPostProcess,
                                  decoder.mDesiredWidth,
                                  decoder.mDesiredHeight,
@@ -821,7 +818,7 @@
     private static native ImageDecoder nCreate(FileDescriptor fd) throws IOException;
     @NonNull
     private static native Bitmap nDecodeBitmap(long nativePtr,
-            OnExceptionListener listener,
+            OnPartialImageListener listener,
             PostProcess postProcess,
             int width, int height,
             Rect cropRect, boolean mutable,
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index dea194e..4571553 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -16,17 +16,12 @@
 
 package android.graphics.drawable;
 
-import android.animation.Animator;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
-import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.FloatProperty;
-import android.view.DisplayListCanvas;
-import android.view.RenderNodeAnimator;
 import android.view.animation.LinearInterpolator;
 
 /**
@@ -78,8 +73,8 @@
 
     private void onStateChanged(boolean animateChanged) {
         float newOpacity = 0.0f;
-        if (mHovered) newOpacity += 1.0f;
-        if (mFocused) newOpacity += 1.0f;
+        if (mHovered) newOpacity += .25f;
+        if (mFocused) newOpacity += .75f;
         if (mAnimator != null) {
             mAnimator.cancel();
             mAnimator = null;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 734cff5..b883656 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -264,8 +264,8 @@
         }
 
         setRippleActive(enabled && pressed);
-
         setBackgroundActive(hovered, focused);
+
         return changed;
     }
 
@@ -879,22 +879,18 @@
         // Grab the color for the current state and cut the alpha channel in
         // half so that the ripple and background together yield full alpha.
         final int color = mState.mColor.getColorForState(getState(), Color.BLACK);
-        final int halfAlpha = (Color.alpha(color) / 2) << 24;
         final Paint p = mRipplePaint;
 
         if (mMaskColorFilter != null) {
             // The ripple timing depends on the paint's alpha value, so we need
             // to push just the alpha channel into the paint and let the filter
             // handle the full-alpha color.
-            final int fullAlphaColor = color | (0xFF << 24);
-            mMaskColorFilter.setColor(fullAlphaColor);
-
-            p.setColor(halfAlpha);
+            mMaskColorFilter.setColor(color | 0xFF000000);
+            p.setColor(color & 0xFF000000);
             p.setColorFilter(mMaskColorFilter);
             p.setShader(mMaskShader);
         } else {
-            final int halfAlphaColor = (color & 0xFFFFFF) | halfAlpha;
-            p.setColor(halfAlphaColor);
+            p.setColor(color);
             p.setColorFilter(null);
             p.setShader(null);
         }
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 13e1ebe..2e08670 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -765,7 +765,8 @@
 
     for (size_t i = start; i < end; i++) {
         glyphs[i - start] = layout.getGlyphId(i);
-        float x = hOffset + layout.getX(i);
+        float halfWidth = layout.getCharAdvance(i) * 0.5f;
+        float x = hOffset + layout.getX(i) + halfWidth;
         float y = vOffset + layout.getY(i);
 
         SkPoint pos;
@@ -776,8 +777,8 @@
         }
         xform[i - start].fSCos = tan.x();
         xform[i - start].fSSin = tan.y();
-        xform[i - start].fTx = pos.x() - tan.y() * y;
-        xform[i - start].fTy = pos.y() + tan.x() * y;
+        xform[i - start].fTx = pos.x() - tan.y() * y - halfWidth * tan.x();
+        xform[i - start].fTy = pos.y() + tan.x() * y - halfWidth * tan.y();
     }
 
     this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanReadback.h b/libs/hwui/pipeline/skia/SkiaVulkanReadback.h
new file mode 100644
index 0000000..65b89d6
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaVulkanReadback.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Readback.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+class SkiaVulkanReadback : public Readback {
+public:
+    SkiaVulkanReadback(renderthread::RenderThread& thread) : Readback(thread) {}
+
+    virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
+            SkBitmap* bitmap) override {
+        //TODO: implement Vulkan readback.
+        return CopyResult::UnknownError;
+    }
+
+    virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
+            SkBitmap* bitmap) override {
+        //TODO: implement Vulkan readback.
+        return CopyResult::UnknownError;
+    }
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 79dc09f..8e0546b 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -24,6 +24,7 @@
 #include "hwui/Bitmap.h"
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "pipeline/skia/SkiaOpenGLReadback.h"
+#include "pipeline/skia/SkiaVulkanReadback.h"
 #include "pipeline/skia/SkiaVulkanPipeline.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/OpenGLPipeline.h"
@@ -158,12 +159,11 @@
                 mReadback = new OpenGLReadbackImpl(*this);
                 break;
             case RenderPipelineType::SkiaGL:
-            case RenderPipelineType::SkiaVulkan:
-                // It works to use the OpenGL pipeline for Vulkan but this is not
-                // ideal as it causes us to create an OpenGL context in addition
-                // to the Vulkan one.
                 mReadback = new skiapipeline::SkiaOpenGLReadback(*this);
                 break;
+            case RenderPipelineType::SkiaVulkan:
+                mReadback = new skiapipeline::SkiaVulkanReadback(*this);
+                break;
             default:
                 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
                 break;
diff --git a/libs/services/Android.bp b/libs/services/Android.bp
new file mode 100644
index 0000000..e5e865f
--- /dev/null
+++ b/libs/services/Android.bp
@@ -0,0 +1,47 @@
+// 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.
+
+// Provides C++ wrappers for system services.
+
+cc_library_shared {
+    name: "libservices",
+    srcs: [
+        ":IDropBoxManagerService.aidl",
+        "src/os/DropBoxManager.cpp",
+        "src/os/StatsLogEventWrapper.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libcutils",
+        "libutils",
+    ],
+    header_libs: [
+	"libbase_headers",
+    ],
+    aidl: {
+        include_dirs: ["frameworks/base/core/java/"],
+    },
+
+    export_include_dirs: ["include"],
+    export_header_lib_headers: ["libbase_headers"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
diff --git a/libs/services/Android.mk b/libs/services/Android.mk
deleted file mode 100644
index d72059a..0000000
--- a/libs/services/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Provides C++ wrappers for system services.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libservices
-LOCAL_SRC_FILES := \
-    ../../core/java/com/android/internal/os/IDropBoxManagerService.aidl \
-    src/os/DropBoxManager.cpp \
-    src/os/StatsLogEventWrapper.cpp
-
-LOCAL_AIDL_INCLUDES := \
-    $(LOCAL_PATH)/../../core/java
-LOCAL_C_INCLUDES := \
-    system/core/include
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    liblog \
-    libcutils \
-    libutils
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_SHARED_LIBRARY)
-
-
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 306ed83..c6496eb 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -680,6 +680,21 @@
     public static final String KEY_LATENCY = "latency";
 
     /**
+     * An optional key describing the maximum number of non-display-order coded frames.
+     * This is an optional parameter that applies only to video encoders. Application should
+     * check the value for this key in the output format to see if codec will produce
+     * non-display-order coded frames. If encoder supports it, the output frames' order will be
+     * different from the display order and each frame's display order could be retrived from
+     * {@link MediaCodec.BufferInfo#presentationTimeUs}. Before API level 27, application may
+     * receive non-display-order coded frames even though the application did not request it.
+     * Note: Application should not rearrange the frames to display order before feeding them
+     * to {@link MediaMuxer#writeSampleData}.
+     * <p>
+     * The default value is 0.
+     */
+    public static final String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
+
+    /**
      * A key describing the desired clockwise rotation on an output surface.
      * This key is only used when the codec is configured using an output surface.
      * The associated value is an integer, representing degrees. Supported values
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
index b57e02d..07483f6 100644
--- a/media/java/android/media/update/ApiLoader.java
+++ b/media/java/android/media/update/ApiLoader.java
@@ -49,8 +49,8 @@
                 Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
         sMediaLibrary = libContext.getClassLoader()
                 .loadClass(UPDATE_CLASS)
-                .getMethod(UPDATE_METHOD, Context.class)
-                .invoke(null, appContext);
+                .getMethod(UPDATE_METHOD, Context.class, Context.class)
+                .invoke(null, appContext, libContext);
         return sMediaLibrary;
     }
 }
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 19f01c2..a1e2404 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.widget.MediaController2;
+import android.widget.VideoView2;
 
 /**
  * Interface for connecting the public API to an updatable implementation.
@@ -31,4 +32,5 @@
 public interface StaticProvider {
     MediaController2Provider createMediaController2(
             MediaController2 instance, ViewProvider superProvider);
+    VideoView2Provider createVideoView2(VideoView2 instance, ViewProvider superProvider);
 }
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
new file mode 100644
index 0000000..6fc9bdc
--- /dev/null
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.update;
+
+import android.media.AudioAttributes;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.widget.MediaController2;
+import android.widget.VideoView2;
+
+import java.util.Map;
+
+/**
+ * Interface for connecting the public API to an updatable implementation.
+ *
+ * Each instance object is connected to one corresponding updatable object which implements the
+ * runtime behavior of that class. There should a corresponding provider method for all public
+ * methods.
+ *
+ * All methods behave as per their namesake in the public API.
+ *
+ * @see android.widget.VideoView2
+ *
+ * @hide
+ */
+// TODO @SystemApi
+public interface VideoView2Provider extends ViewProvider {
+    void start_impl();
+    void pause_impl();
+    int getDuration_impl();
+    int getCurrentPosition_impl();
+    void seekTo_impl(int msec);
+    boolean isPlaying_impl();
+    int getBufferPercentage_impl();
+    int getAudioSessionId_impl();
+    void showSubtitle_impl();
+    void hideSubtitle_impl();
+    void setAudioFocusRequest_impl(int focusGain);
+    void setAudioAttributes_impl(AudioAttributes attributes);
+    void setVideoPath_impl(String path);
+    void setVideoURI_impl(Uri uri);
+    void setVideoURI_impl(Uri uri, Map<String, String> headers);
+    void setMediaController2_impl(MediaController2 controllerView);
+    void setViewType_impl(int viewType);
+    int getViewType_impl();
+    void stopPlayback_impl();
+    void setOnPreparedListener_impl(MediaPlayer.OnPreparedListener l);
+    void setOnCompletionListener_impl(MediaPlayer.OnCompletionListener l);
+    void setOnErrorListener_impl(MediaPlayer.OnErrorListener l);
+    void setOnInfoListener_impl(MediaPlayer.OnInfoListener l);
+    void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l);
+}
diff --git a/native/android/net.c b/native/android/net.c
index de4b90c..60296a7 100644
--- a/native/android/net.c
+++ b/native/android/net.c
@@ -27,7 +27,7 @@
     static const uint32_t k32BitMask = 0xffffffff;
     // This value MUST be kept in sync with the corresponding value in
     // the android.net.Network#getNetworkHandle() implementation.
-    static const uint32_t kHandleMagic = 0xfacade;
+    static const uint32_t kHandleMagic = 0xcafed00d;
 
     // Check for minimum acceptable version of the API in the low bits.
     if (handle != NETWORK_UNSPECIFIED &&
diff --git a/packages/BackupRestoreConfirmation/res/values-ar/strings.xml b/packages/BackupRestoreConfirmation/res/values-ar/strings.xml
index 4d4d6be..810b1e7 100644
--- a/packages/BackupRestoreConfirmation/res/values-ar/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ar/strings.xml
@@ -21,7 +21,7 @@
     <string name="backup_confirm_text" msgid="1878021282758896593">"تم طلب الاحتفاظ بنسخة احتياطية كاملة من البيانات على كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟\n\nإذا لم تطلب الاحتفاظ بنسخة احتياطية بنفسك، فلا تسمح بمتابعة العملية."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"الاحتفاظ بنسخة احتياطية من بياناتي"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"عدم النسخ الاحتياطي"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"تم طلب استرداد جميع البيانات بالكامل من كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟\n\nإذا لم تطلب الاسترداد بنفسك، فلا تسمح بمتابعة العملية. يؤدي لك إلى استبدال أية بيانات حاليًا على الجهاز."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"تم طلب استرداد جميع البيانات بالكامل من كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟\n\nإذا لم تطلب الاسترداد بنفسك، فلا تسمح بمتابعة العملية. يؤدي لك إلى استبدال أي بيانات حاليًا على الجهاز."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"استرداد بياناتي"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"عدم الاسترداد"</string>
     <string name="current_password_text" msgid="8268189555578298067">"يُرجى إدخال كلمة مرور النسخ الاحتياطي أدناه:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-pt-rBR/strings.xml b/packages/BackupRestoreConfirmation/res/values-pt-rBR/strings.xml
index cbc579e..baa4867 100644
--- a/packages/BackupRestoreConfirmation/res/values-pt-rBR/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-pt-rBR/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Backup completo"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restauração completa"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Deseja permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Quer permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Fazer backup de meus dados"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Não fazer backup"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Deseja permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Quer permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar meus dados"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Não restaurar"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Digite sua senha de backup atual abaixo:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-pt/strings.xml b/packages/BackupRestoreConfirmation/res/values-pt/strings.xml
index cbc579e..baa4867 100644
--- a/packages/BackupRestoreConfirmation/res/values-pt/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-pt/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Backup completo"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restauração completa"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Deseja permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Quer permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Fazer backup de meus dados"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Não fazer backup"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Deseja permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Quer permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar meus dados"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Não restaurar"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Digite sua senha de backup atual abaixo:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
index 530efc0..ed75344 100644
--- a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Kuhifadhi kikamilifu"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejesha kila kitu"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Ombi la kuhifadhi nakala rudufu kamili za data kwenye eneo kazi la kompyuta iliyounganishwa limewasilishwa. Ungependa shughuli hii ufanyike?\n\n Ikiwa sio wewe uliyewasilisha ombi hili, usikubali shughuli hii iendelee."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Ombi la kuhifadhi nakala kamili za data kwenye eneo kazi la kompyuta iliyounganishwa limewasilishwa. Ungependa shughuli hii ufanyike?\n\n Ikiwa si wewe uliyewasilisha ombi hili, usikubali shughuli hii iendelee."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Hifadhi nakala ya data yangu"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Usicheleze"</string>
     <string name="restore_confirm_text" msgid="7499866728030461776">"Kurejesha kamili kwa data nzima kutoka kwa eneo kazi la kompyuta lililounganishwa limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuweza kurejesha upya mwenyewe, usiruhusu uendeshaji huu kuendelea. Hii itaweka upya data yoyote iliyo kwenye kifaa hiki sasa!"</string>
diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml
index 7edbb11..ad2fc24 100644
--- a/packages/CarrierDefaultApp/res/values-bs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml
@@ -4,12 +4,12 @@
     <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
     <string name="android_system_label" msgid="2797790869522345065">"Mobilni operater"</string>
     <string name="portal_notification_id" msgid="5155057562457079297">"Mobilni internet je potrošen"</string>
-    <string name="no_data_notification_id" msgid="668400731803969521">"Prijenos mobilnih podataka je deaktiviran"</string>
+    <string name="no_data_notification_id" msgid="668400731803969521">"Prijenos podataka na mobilnoj mreži je deaktiviran"</string>
     <string name="portal_notification_detail" msgid="2295729385924660881">"Dodirnite da posjetite %s web lokaciju"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"Obratite se pružaocu usluga %s"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Nema mobilnog prijenosa podataka"</string>
     <string name="no_mobile_data_connection" msgid="544980465184147010">"Dodajte plan prijenosa podataka ili rominga putem operatera %s"</string>
-    <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Status mobilnih podataka"</string>
+    <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Status prijenosa podataka na mobilnoj mreži"</string>
     <string name="action_bar_label" msgid="4290345990334377177">"Prijava na mobilnu mrežu"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"Mreža kojoj pokušavate pristupiti ima sigurnosnih problema."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Naprimjer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
diff --git a/packages/InputDevices/res/values-en-rAU/strings.xml b/packages/InputDevices/res/values-en-rAU/strings.xml
index 9217bc4..8f37882 100644
--- a/packages/InputDevices/res/values-en-rAU/strings.xml
+++ b/packages/InputDevices/res/values-en-rAU/strings.xml
@@ -42,4 +42,5 @@
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
     <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string>
     <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string>
+    <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rCA/strings.xml b/packages/InputDevices/res/values-en-rCA/strings.xml
index 9217bc4..8f37882 100644
--- a/packages/InputDevices/res/values-en-rCA/strings.xml
+++ b/packages/InputDevices/res/values-en-rCA/strings.xml
@@ -42,4 +42,5 @@
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
     <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string>
     <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string>
+    <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml
index 9217bc4..8f37882 100644
--- a/packages/InputDevices/res/values-en-rGB/strings.xml
+++ b/packages/InputDevices/res/values-en-rGB/strings.xml
@@ -42,4 +42,5 @@
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
     <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string>
     <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string>
+    <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml
index 9217bc4..8f37882 100644
--- a/packages/InputDevices/res/values-en-rIN/strings.xml
+++ b/packages/InputDevices/res/values-en-rIN/strings.xml
@@ -42,4 +42,5 @@
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
     <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string>
     <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string>
+    <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rXC/strings.xml b/packages/InputDevices/res/values-en-rXC/strings.xml
index 43d7677..bc1b234 100644
--- a/packages/InputDevices/res/values-en-rXC/strings.xml
+++ b/packages/InputDevices/res/values-en-rXC/strings.xml
@@ -42,4 +42,5 @@
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎Spanish (Latin)‎‏‎‎‏‎"</string>
     <string name="keyboard_layout_latvian" msgid="4405417142306250595">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎Latvian‎‏‎‎‏‎"</string>
     <string name="keyboard_layout_persian" msgid="3920643161015888527">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎Persian‎‏‎‎‏‎"</string>
+    <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‏‏‎Azerbaijani‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index eab784d..f1fd93b 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -56,7 +56,7 @@
     <string name="print_select_printer" msgid="7388760939873368698">"حدد الطابعة"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"تجاهل الطابعة"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
-      <item quantity="zero">لم يتم العثور على أية طابعة (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item>
+      <item quantity="zero">لم يتم العثور على أي طابعة (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item>
       <item quantity="two">تم العثور على طابعتين (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item>
       <item quantity="few">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
       <item quantity="many">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> طابعة</item>
diff --git a/packages/PrintSpooler/res/values-mr/strings.xml b/packages/PrintSpooler/res/values-mr/strings.xml
index 862d193..7fe9c8c 100644
--- a/packages/PrintSpooler/res/values-mr/strings.xml
+++ b/packages/PrintSpooler/res/values-mr/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="4469836075319831821">"स्पूलर मुद्रण"</string>
+    <string name="app_label" msgid="4469836075319831821">"स्पूलर प्रिंट"</string>
     <string name="more_options_button" msgid="2243228396432556771">"अधिक पर्याय"</string>
     <string name="label_destination" msgid="9132510997381599275">"गंतव्यस्‍थान"</string>
     <string name="label_copies" msgid="3634531042822968308">"प्रती"</string>
@@ -31,22 +31,22 @@
     <string name="template_all_pages" msgid="3322235982020148762">"सर्व <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
     <string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> ची श्रेणी"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"उदा. 1—5,8,11—13"</string>
-    <string name="print_preview" msgid="8010217796057763343">"मुद्रण पूर्वावलोकन"</string>
+    <string name="print_preview" msgid="8010217796057763343">"प्रिंट पूर्वावलोकन"</string>
     <string name="install_for_print_preview" msgid="6366303997385509332">"पूर्वावलोकनासाठी पीडीएफ व्ह्यूअर इंस्टॉल करा"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"प्रिंटिंग अ‍ॅप क्रॅश झाले"</string>
-    <string name="generating_print_job" msgid="3119608742651698916">"मुद्रण कार्य व्‍युत्‍पन्न करत आहे"</string>
+    <string name="generating_print_job" msgid="3119608742651698916">"प्रिंट कार्य व्‍युत्‍पन्न करत आहे"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"पीडीएफ म्‍हणून सेव्ह करा"</string>
     <string name="all_printers" msgid="5018829726861876202">"सर्व प्रिंटर..."</string>
-    <string name="print_dialog" msgid="32628687461331979">"मुद्रण संवाद"</string>
+    <string name="print_dialog" msgid="32628687461331979">"प्रिंट संवाद"</string>
     <string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
     <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g> पैकी <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> पृष्‍ठ"</string>
     <string name="summary_template" msgid="8899734908625669193">"सारांश, प्रती <xliff:g id="COPIES">%1$s</xliff:g>, कागद आकार <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
     <string name="expand_handle" msgid="7282974448109280522">"विस्तृत करण्याचे हँडल"</string>
     <string name="collapse_handle" msgid="6886637989442507451">"संक्षिप्त करण्याचे हँडल"</string>
-    <string name="print_button" msgid="645164566271246268">"मुद्रण करा"</string>
+    <string name="print_button" msgid="645164566271246268">"प्रिंट करा"</string>
     <string name="savetopdf_button" msgid="2976186791686924743">"पीडीएफ वर सेव्ह करा"</string>
-    <string name="print_options_expanded" msgid="6944679157471691859">"मुद्रण पर्याय विस्तृत झाले"</string>
-    <string name="print_options_collapsed" msgid="7455930445670414332">"मुद्रण पर्याय संक्षिप्त झाले"</string>
+    <string name="print_options_expanded" msgid="6944679157471691859">"प्रिंट पर्याय विस्तृत झाले"</string>
+    <string name="print_options_collapsed" msgid="7455930445670414332">"प्रिंट पर्याय संक्षिप्त झाले"</string>
     <string name="search" msgid="5421724265322228497">"शोध"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"सर्व प्रिंटर"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"सेवा जोडा"</string>
@@ -64,9 +64,9 @@
     <string name="notification_channel_progress" msgid="872788690775721436">"प्रिंट कार्ये चालवणे"</string>
     <string name="notification_channel_failure" msgid="9042250774797916414">"अयशस्वी प्रिंट कार्ये"</string>
     <string name="could_not_create_file" msgid="3425025039427448443">"फाईल तयार करणेे शक्य झाले नाही"</string>
-    <string name="print_services_disabled_toast" msgid="9089060734685174685">"काही मुद्रण सेवा अक्षम केल्या आहेत"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"काही प्रिंट सेवा अक्षम केल्या आहेत"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर शोधत आहे"</string>
-    <string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही मुद्रण सेवा सक्षम केलेल्या नाहीत"</string>
+    <string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही प्रिंट सेवा सक्षम केलेल्या नाहीत"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"कोणतेही प्रिंटर आढळले नाही"</string>
     <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिंटर जोडू शकत नाही"</string>
     <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिंटर जोडण्यासाठी निवडा"</string>
@@ -79,7 +79,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी इंस्टॉल करा</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी इंस्टॉल करा</item>
     </plurals>
-    <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करत आहे"</string>
+    <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> प्रिंट करत आहे"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करत आहे"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर एरर <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> अवरोधित केले"</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index 8b00ed0..faa10cc 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -23,6 +23,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodManager;
+
 import com.android.printspooler.R;
 
 /**
@@ -410,7 +411,7 @@
 
             mPrintButton.offsetTopAndBottom(dy);
 
-            mDraggableContent.notifySubtreeAccessibilityStateChangedIfNeeded();
+            mDraggableContent.notifyAccessibilitySubtreeChanged();
 
             onDragProgress(progress);
         }
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index 9d1c4ca..14f0625 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -55,7 +55,6 @@
 
 # Include android-support-v14-preference, if not already included
 ifeq (,$(findstring android-support-v14-preference,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v14/preference/res
 LOCAL_AAPT_FLAGS += --extra-packages android.support.v14.preference
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v14-preference
 endif
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 5652ad9..ff81fc1 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardewareversnelling vir verbinding"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Wys Bluetooth-toestelle sonder name"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiveer absolute volume"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Aktiveer inband-luitoon"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-weergawe"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Kies Bluetooth AVRCP-weergawe"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-oudiokodek"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontroleer programme wat via ADB/ADT geïnstalleer is vir skadelike gedrag."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-toestelle sonder name (net MAC-adresse) sal gewys word"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiveer die Bluetooth-kenmerk vir absolute volume indien daar volumeprobleme met afgeleë toestelle is, soos onaanvaarbare harde klank of geen beheer nie."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Laat toe dat luitone op die foon op Bluetooth-kopstukke gespeel word"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Plaaslike terminaal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Aktiveer terminaalprogram wat plaaslike skermtoegang bied"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrolering"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4aac238..111b7cf 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"የሃርድዌር ማቀላጠፊያን በማስተሳሰር ላይ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"የብሉቱዝ መሣሪያዎችን ያለ ስሞች አሳይ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ፍጹማዊ ድምፅን አሰናክል"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"የውስጠ-ሞገድ ማስጮህን አንቃ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"የብሉቱዝ AVRCP ስሪት"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"የብሉቱዝ AVRCP ስሪት ይምረጡ"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"የብሉቱዝ ኦዲዮ ኮዴክ"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"በADB/ADT በኩል የተጫኑ መተግበሪያዎች ጎጂ ባህሪ ካላቸው ያረጋግጡ።"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"የብሉቱዝ መሣሪያዎች ያለ ስሞች (MAC አድራሻዎች ብቻ) ይታያሉ"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"እንደ ተቀባይነት በሌለው ደረጃ ድምፁ ከፍ ማለት ወይም መቆጣጠር አለመቻል ያሉ ከሩቅ መሣሪያዎች ጋር የድምፅ ችግር በሚኖርበት ጊዜ የብሉቱዝ ፍጹማዊ ድምፅን ባሕሪ ያሰናክላል።"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"በስልኩ ላይ ያሉ የጥሪ ቅላጼዎች በብሉቱዝ ጆሮ ማዳመጫዎች ላይ እንዲጫወቱ ፍቀድ"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"አካባቢያዊ ተርሚናል"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"የአካባቢያዊ ሼል መዳረሻ የሚያቀርብ የተርሚናል መተግበሪያ አንቃ"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"የHDCP ምልከታ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 90cc221..b101a1d 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"تسريع الأجهزة للتوصيل"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"عرض أجهزة البلوتوث بدون أسماء"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"تعطيل مستوى الصوت المطلق"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"تمكين الرنين ضمن النطاق الأساسي"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‏إصدار Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"‏اختيار إصدار Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ترميز صوت بلوتوث"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏التحقق من التطبيقات المثبتة عبر ADB/ADT لكشف السلوك الضار"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"‏سيتم عرض أجهزة البلوتوث بدون أسماء (عناوين MAC فقط)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"لتعطيل ميزة مستوى الصوت المطلق للبلوتوث في حالة حدوث مشكلات متعلقة بمستوى الصوت مع الأجهزة البعيدة مثل مستوى صوت عالٍ بشكل غير مقبول أو نقص إمكانية التحكم في الصوت."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"السماح بتشغيل نغمات الرنين على الهاتف من خلال سماعات الرأس البلوتوث"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"تطبيق طرفي محلي"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"تمكين تطبيق طرفي يوفر إمكانية الدخول إلى واجهة النظام المحلية"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"‏التحقق من HDCP"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 1053079..03c9b92 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Birləşmə üçün avadanlıq akselerasiyası"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bluetooth cihazlarını adsız göstərin"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Mütləq səs həcmi deaktiv edin"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Diapazon daxili zəngi aktiv edin"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Versiya"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP Versiyasını seçin"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Kodek"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT vasitəsi ilə quraşdırılmış tətbiqləri zərərli davranış üzrə yoxlayın."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Adsız Bluetooth cihazları (yalnız MAC ünvanları) göstəriləcək"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Uzaqdan idarə olunan cihazlarda dözülməz yüksək səs həcmi və ya nəzarət çatışmazlığı kimi səs problemləri olduqda Bluetooth mütləq səs həcmi xüsusiyyətini deaktiv edir."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Telefondakı bütün melodiyaların Bluetooth qulaqlıqlarında oxudulmasına icazə verin"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Yerli terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Yerli örtük girişini təklif edən terminal tətbiqi aktiv edin"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP yoxlanılır"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 5239f5a..62e4b4c 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzanje privezivanja"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Prikaži Bluetooth uređaje bez naziva"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući glavno podešavanje jačine zvuka"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Omogućavanje zvonjave na istom kanalu"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Verzija Bluetooth AVRCP-a"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Izaberite verziju Bluetooth AVRCP-a"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodek"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Proverava da li su aplikacije instalirane preko ADB-a/ADT-a štetne."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Biće prikazani Bluetooth uređaji bez naziva (samo sa MAC adresama)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućava glavno podešavanje jačine zvuka na Bluetooth uređaju u slučaju problema sa jačinom zvuka na daljinskim uređajima, kao što su izuzetno velika jačina zvuka ili nedostatak kontrole."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Omogućite da se melodija zvona na telefonu pušta preko Bluetooth slušalica"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Omogući aplik. terminala za pristup lokalnom komandnom okruženju"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provera"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index c6aa478..c648ea5 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Апаратнае паскарэнне ў рэжыме мадэма"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Паказваць прылады Bluetooth без назваў"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Адключыць абсалютны гук"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Уключыць унутрыпалосны празвон"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Версія Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Выбраць версію Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодэк Bluetooth Audio"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Праверце прыкладаннi, усталяваныя з дапамогай ADB/ADT, на нестабiльныя паводзiны."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Прылады Bluetooth будуць паказаны без назваў (толькі MAC-адрасы)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Адключыць функцыю абсалютнага гуку Bluetooth у выпадку праблем з гукам на аддаленых прыладах, напр., пры непрымальна высокай гучнасці або адсутнасці кіравання."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Дазволіць прайграванне рынгтонаў на тэлефоне праз гарнітуры Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Лакальны тэрмінал"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Уключэнне прыкладання тэрмінала, якое прапануе доступ да лакальнай абалонкі"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Праверка HDCP"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index c932c83..83c1ec0 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардуерно ускорение за тетъринга"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Показване на устройствата с Bluetooth без имена"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Деактивиране на пълната сила на звука"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Активиране на звъненето в една и съща честотна лента"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Версия на AVRCP за Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Избиране на версия на AVRCP за Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Аудиокодек за Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверка на инсталираните чрез ADB/ADT приложения за опасно поведение."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Ще бъдат показани устройствата с Bluetooth без имена (само MAC адресите)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Деактивира функцията на Bluetooth за пълна сила на звука в случай на проблеми със звука на отдалечени устройства, като например неприемливо висока сила на звука или липса на управление."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Разрешаване на мелодиите на телефона да се възпроизвеждат на слушалките с Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Локален терминал"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Актив. на прил. за терминал с достъп до локалния команден ред"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Проверка с HDCP"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index a5c2e41..baf9e2c 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"নামহীন ব্লুটুথ ডিভাইসগুলি দেখুন"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"চূড়ান্ত ভলিউম অক্ষম করুন"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ইন-ব্যান্ড রিং করা সক্ষম করুন"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ব্লুটুথ AVRCP ভার্সন"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ব্লুটুথ AVRCP ভার্সন বেছে নিন"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ব্লুটুথ অডিও কোডেক"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ক্ষতিকারক ক্রিয়াকলাপ করছে কিনা তার জন্য ADB/ADT মারফত ইনস্টল করা অ্যাপ্লিকেশানগুলি চেক করুন।"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"নামহীন ব্লুটুথ ডিভাইসগুলি দেখানো হবে (শুধুমাত্র MAC ঠিকানা)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"অপ্রত্যাশিত উচ্চ ভলিউম বা নিয়ন্ত্রণের অভাবের মত দূরবর্তী ডিভাইসের ভলিউম সমস্যাগুলির ক্ষেত্রে, ব্লুটুথ চুড়ান্ত ভলিউম বৈশিষ্ট্য অক্ষম করে৷"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ফোনের রিংটোন ব্লুটুথ হেডসেটে শোনা সক্ষম করুন"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"স্থানীয় টার্মিনাল"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"স্থানীয় শেল অ্যাক্সেসের প্রস্তাব করে এমন টার্মিনাল অ্যাপ্লিকেশন সক্ষম করুন"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP পরীক্ষণ"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index ed0958c..88b01e9 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzavanje dijeljenja veze"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Prikaži Bluetooth uređaje bez naziva"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogućite apsolutnu jačinu zvuka"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Omogući zvono unutar pojasa"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP verzija"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Odaberite Bluetooth AVRCP verziju"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio kodek"</string>
@@ -225,7 +224,7 @@
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži opcije za certifikaciju Bežičnog prikaza"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećajte nivo Wi-Fi zapisivanja, pokazati po SSID RSSI Wi-Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kada je omogućeno, Wi-Fi veza će u slučaju slabog signala agresivnije predavati vezu za prijenos podataka na mobilnu vezu"</string>
-    <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Dozvoli/Zabrani Wi-Fi lutajuće skeniranje na osnovu količine podatkovnog prometa prisutnog na interfejsu"</string>
+    <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Dozvoli/Zabrani Wi-Fi lutajuće skeniranje na osnovu količine podatkovnog saobraćaja prisutnog na interfejsu"</string>
     <string name="select_logd_size_title" msgid="7433137108348553508">"Veličine bafera za zapisnik"</string>
     <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Odaberite veličine za Logger prema međumemoriji evidencije"</string>
     <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Želite li izbrisati trajnu pohranu zapisivača?"</string>
@@ -237,7 +236,7 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"Dozvoli lažne lokacije"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"Dozvoli lažne lokacije"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"Omogući pregled atributa prikaza"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Uvijek drži mobilne podatke aktivnim, čak i kada je Wi-Fi je aktivan (za brzo prebacivanje između mreža)."</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Uvijek drži prijenos podataka na mobilnoj mreži aktivnim, čak i kada je Wi-Fi je aktivan (za brzo prebacivanje između mreža)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Koristi hardversko ubrzavanje dijeljenja veze, ako je dostupno"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"Omogućiti otklanjanje grešaka putem uređaja spojenog na USB?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"Otklanjanje grešaka putem uređaja spojenog na USB je namijenjeno samo u svrhe razvoja aplikacija. Koristite ga za kopiranje podataka između računara i uređaja, instaliranje aplikacija na uređaj bez obavještenja te čitanje podataka iz zapisnika."</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerava da li se u aplikacijama instaliranim putem ADB-a/ADT-a javlja zlonamerno ponašanje."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Prikazat će se Bluetooth uređaji bez naziva (samo MAC adrese)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućava opciju Bluetooth apsolutne jačine zvuka u slučaju problema s jačinom zvuka na udaljenim uređajima, kao što je neprihvatljivo glasan zvuk ili nedostatak kontrole."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Dopusti da se melodije zvona reproduciranju na Bluetooth slušalicama"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Omogući terminalnu aplik. koja nudi pristup lok. kom. okruženju"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provjeravanje"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index e65adcd..48223ce 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Acceleració per maquinari per compartir la xarxa"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostra els dispositius Bluetooth sense el nom"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactiva el volum absolut"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activa el so al mateix canal"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versió AVRCP de Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecciona la versió AVRCP de Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Còdec d\'àudio per Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprova les aplicacions instal·lades mitjançant ADB/ADT per detectar possibles comportaments perillosos"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Es mostraran els dispositius Bluetooth sense el nom (només l\'adreça MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desactiva la funció de volum absolut del Bluetooth en cas que es produeixin problemes de volum amb dispositius remots, com ara un volum massa alt o una manca de control."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permet que els sons de trucada del telèfon es reprodueixin en auriculars Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Activa l\'aplicació de terminal que ofereix accés al shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Comprovació HDCP"</string>
@@ -358,14 +356,14 @@
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="845431008899029842">"Temps restant aproximat: <xliff:g id="TIME">^1</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME">^1</xliff:g>"</string>
-    <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">^1</xliff:g> per completar la càrrega"</string>
+    <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">^1</xliff:g> per completar la pujada"</string>
     <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Temps restant: <xliff:g id="TIME">^1</xliff:g>"</string>
     <string name="power_remaining_duration_only_short_enhanced" msgid="7450425624026394823">"Temps restant segons l\'ús que en fas: <xliff:g id="TIME">^1</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">^1</xliff:g>: <xliff:g id="TIME">^2</xliff:g> aproximadament per esgotar la bateria"</string>
     <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">^1</xliff:g>; temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME">^2</xliff:g>"</string>
     <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">^1</xliff:g>; temps restant: <xliff:g id="TIME">^2</xliff:g>"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
-    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">^1</xliff:g>: <xliff:g id="TIME">^2</xliff:g> per completar la càrrega"</string>
+    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">^1</xliff:g>: <xliff:g id="TIME">^2</xliff:g> per completar la pujada"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Desconegut"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"S\'està carregant"</string>
     <string name="battery_info_status_charging_lower" msgid="8689770213898117994">"s\'està carregant"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 771a32d..88bbaa7 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwarová akcelerace tetheringu"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Zobrazovat zařízení Bluetooth bez názvů"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zakázat absolutní hlasitost"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Povolit vyzvánění v hovorovém pásmu"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Verze profilu Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Vyberte verzi profilu Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio – kodek"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolovat škodlivost aplikací nainstalovaných pomocí nástroje ADB/ADT"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Zařízení Bluetooth se budou zobrazovat bez názvů (pouze adresy MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Zakáže funkci absolutní hlasitosti Bluetooth. Zabrání tak problémům s hlasitostí vzdálených zařízení (jako je příliš vysoká hlasitost nebo nemožnost ovládání)."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Umožňuje přehrávat vyzváněcí tóny z telefonu v náhlavní soupravě Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Místní terminál"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Aktivovat terminálovou aplikaci pro místní přístup k prostředí shell"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrola HDCP"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index c3cfdff..6f36bc5 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwareacceleration ved netdeling"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Vis Bluetooth-enheder uden navne"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiver absolut lydstyrke"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Afspil ringetone via Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"AVRCP-version for Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Vælg AVRCP-version for Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-lydcodec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tjek apps, der er installeret via ADB/ADT, for skadelig adfærd."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-enheder uden navne (kun MAC-adresser) vises"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiverer funktionen til absolut lydstyrke via Bluetooth i tilfælde af problemer med lydstyrken på eksterne enheder, f.eks. uacceptabel høj lyd eller manglende kontrol."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Tillad, at ringetoner på telefonen kan afspilles i Bluetooth-headset"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Aktivér terminalappen, der giver lokal shell-adgang"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrol"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index d12ac8a..4d53e2d 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwarebeschleunigung für Tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bluetooth-Geräte ohne Namen anzeigen"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Maximallautstärke deaktivieren"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"In-Band-Klingeln aktivieren"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-Version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP-Version auswählen"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-Audio-Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Überprüft installierte Apps über ADB/ADT auf schädliches Verhalten"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-Geräte ohne Namen (nur MAC-Adressen) werden angezeigt"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiviert die Bluetooth-Maximallautstärkefunktion, falls auf Remote-Geräten Probleme mit der Lautstärke auftreten, wie beispielsweise übermäßig laute Wiedergabe oder fehlende Kontrolle bei der Steuerung."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Wiedergabe von Smartphone-Klingeltönen auf Bluetooth-Headsets zulassen"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokales Terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Terminal-App mit Zugriff auf lokale Shell aktivieren"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-Prüfung"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 9552c73..e510356 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Σύνδεση επιτάχυνσης υλικού"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Εμφάνιση συσκευών Bluetooth χωρίς ονόματα"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Απενεργοποίηση απόλυτης έντασης"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ενεργοποίηση κλήσης εντός εύρους"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Έκδοση AVRCP Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Επιλογή έκδοσης AVRCP Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Κωδικοποιητής ήχου Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Έλεγχος εφαρμογών που έχουν εγκατασταθεί μέσω ADB/ADT για επιβλαβή συμπεριφορά."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Θα εμφανιστούν οι συσκευές Bluetooth χωρίς ονόματα (μόνο διευθύνσεις MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Απενεργοποιεί τη δυνατότητα απόλυτης έντασης του Bluetooth σε περίπτωση προβλημάτων έντασης με απομακρυσμένες συσκευές, όπως όταν υπάρχει μη αποδεκτά υψηλή ένταση ή απουσία ελέγχου."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Να επιτρέπεται η αναπαραγωγή των ήχων κλήσης του τηλεφώνου στα ακουστικά Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Τοπική τερματική εφαρμογή"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Ενεργοπ.τερμ.εφαρμογής που προσφέρει πρόσβαση στο τοπικό κέλυφος"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Έλεγχος HDCP"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 53b5d9e..a322388 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Show Bluetooth devices without names"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Enable in-band ringing"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Select Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth devices without names (MAC addresses only) will be displayed"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Allow ringtones on the phone to be played on Bluetooth headsets"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 53b5d9e..a322388 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Show Bluetooth devices without names"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Enable in-band ringing"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Select Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth devices without names (MAC addresses only) will be displayed"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Allow ringtones on the phone to be played on Bluetooth headsets"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 53b5d9e..a322388 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Show Bluetooth devices without names"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Enable in-band ringing"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Select Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth devices without names (MAC addresses only) will be displayed"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Allow ringtones on the phone to be played on Bluetooth headsets"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 53b5d9e..a322388 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Show Bluetooth devices without names"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Enable in-band ringing"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Select Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth devices without names (MAC addresses only) will be displayed"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Allow ringtones on the phone to be played on Bluetooth headsets"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 2b0b6e5..80c2eb8 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‎Tethering hardware acceleration‎‏‎‎‏‎"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‎‎Show Bluetooth devices without names‎‏‎‎‏‎"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎Disable absolute volume‎‏‎‎‏‎"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‎‎Enable in-band ringing‎‏‎‎‏‎"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎Bluetooth AVRCP Version‎‏‎‎‏‎"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‎‏‏‎‎Select Bluetooth AVRCP Version‎‏‎‎‏‎"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎Bluetooth Audio Codec‎‏‎‎‏‎"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎Check apps installed via ADB/ADT for harmful behavior.‎‏‎‎‏‎"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎Bluetooth devices without names (MAC addresses only) will be displayed‎‏‎‎‏‎"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control.‎‏‎‎‏‎"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎Allow ringtones on the phone to be played on Bluetooth headsets‎‏‎‎‏‎"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎Local terminal‎‏‎‎‏‎"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎Enable terminal app that offers local shell access‎‏‎‎‏‎"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎HDCP checking‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index c36b3ed..65000b3 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración de hardware de conexión mediante dispositivo portátil"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sin nombre"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Habilitar sonido dentro de banda"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión de AVRCP del Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecciona la versión de AVRCP del Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec del audio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar que las aplicaciones instaladas mediante ADB/ADT no ocasionen daños"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Se mostrarán los dispositivos Bluetooth sin nombre (solo direcciones MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inhabilita la función de volumen absoluto de Bluetooth si se producen problemas de volumen con dispositivos remotos (por ejemplo, volumen demasiado alto o falta de control)."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permite que los tonos del teléfono suenen en auriculares Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Habilitar aplicac. de terminal que ofrece acceso al shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación HDCP"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 1f57e48..2a5e41b 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración por hardware para conexión compartida"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sin nombre"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Habilitar tono de llamada por Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión AVRCP del Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecciona la versión AVRCP del Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec de audio por Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprueba las aplicaciones instaladas mediante ADB/ADT para detectar comportamientos dañinos"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Se mostrarán dispositivos Bluetooth sin nombre (solo direcciones MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inhabilita la función de volumen absoluto de Bluetooth si se producen problemas de volumen con dispositivos remotos (por ejemplo, volumen demasiado alto o falta de control)."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permite que los tonos de llamada del teléfono se reproduzcan en auriculares Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Habilitar aplicación de terminal que ofrece acceso a shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación de HDCP"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 361d14d..a8ac99f 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Jagamise riistvaraline kiirendus"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Kuva Bluetoothi seadmed ilma nimedeta"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Keela absoluutne helitugevus"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Luba ribasisene helisemine"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetoothi AVRCP versioon"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Valige Bluetoothi AVRCP versioon"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetoothi heli kodek"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolli, kas ADB/ADT-ga installitud rakendused on ohtlikud."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Kuvatakse ilma nimedeta (ainult MAC-aadressidega) Bluetoothi seadmed"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Keelatakse Bluetoothi absoluutse helitugevuse funktsioon, kui kaugseadmetega on helitugevuse probleeme (nt liiga vali heli või juhitavuse puudumine)."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Lubab telefonis olevaid helinaid esitada Bluetoothi peakomplektides"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Kohalik terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Luba kohalikku turvalist juurdepääsu pakkuv terminalirakendus"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrollimine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 22e9d35..2c81f2e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Konexioa partekatzeko hardwarearen azelerazioa"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Erakutsi Bluetooth gailuak izenik gabe"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desgaitu bolumen absolutua"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Gaitu tonuak audio-kanal berean erreproduzitzeko aukera"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP bertsioa"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Hautatu Bluetooth AVRCP bertsioa"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth bidezko audioaren kodeka"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak antzemateko."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth gailuak izenik gabe (MAC helbideak soilik) erakutsiko dira"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desgaitu egiten du Bluetooth bidezko bolumen absolutuaren eginbidea urruneko gailuetan arazoak hautematen badira; esaterako, bolumena ozenegia bada edo ezin bada kontrolatu."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Onartu telefonoko tonuak Bluetooth entzungailuetan erreproduzitzeko aukera"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Tokiko terminala"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Gaitu tokiko shell-sarbidea duen terminal-aplikazioa"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP egiaztapena"</string>
@@ -353,7 +351,7 @@
     <string name="daltonizer_mode_deuteranomaly" msgid="5475532989673586329">"Daltonismoa (gorri-berdeak)"</string>
     <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"Protanopia (gorri-berdeak)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="481725854987912389">"Tritanopia (urdin-horia)"</string>
-    <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kolorearen zuzenketa"</string>
+    <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Koloreen zuzenketa"</string>
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Eginbidea esperimentala da eta eragina izan dezake funtzionamenduan."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
     <string name="power_remaining_duration_only" msgid="845431008899029842">"<xliff:g id="TIME">^1</xliff:g> inguru gelditzen dira"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 35917bb..4f3c77f 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"شتاب سخت‌افزاری اتصال به اینترنت با تلفن همراه"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"نمایش دستگاه‌های بلوتوث بدون نام"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"غیرفعال کردن میزان صدای مطلق"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"فعال کردن زنگ زدن درون باندی"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‏نسخه AVRCP بلوتوث"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"‏انتخاب نسخه AVRCP بلوتوث"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"کدک بلوتوث صوتی"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏برنامه‌های نصب شده از طریق ADB/ADT را ازنظر رفتار مخاطره‌آمیز بررسی کنید."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"‏دستگاه‌های بلوتوث بدون نام (فقط نشانی‌های MAC) نشان داده خواهند شد"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"در صورت وجود مشکل میزان صدا با دستگاه‌های راه دور مثل میزان صدای بلند ناخوشایند یا عدم کنترل صدا، قابلیت میزان صدای کامل بلوتوث را غیرفعال کنید."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"اجازه می‌دهد آهنگ‌های زنگ تلفن در هدست‌های بلوتوث پخش شود"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"ترمینال محلی"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"فعال کردن ترمینال برنامه‌ کاربردی که دسترسی به برنامه محلی را پیشنهاد می‌کند"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"‏بررسی HDCP"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 869490a..5932d00 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Laitteistokiihdytyksen yhteyden jakaminen"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Näytä nimettömät Bluetooth-laitteet"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Poista yleinen äänenvoimakkuuden säätö käytöstä"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ota käyttöön kaistalla soitto"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetoothin AVRCP-versio"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Valitse Bluetoothin AVRCP-versio"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-äänen koodekki"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tarkista ADB:n/ADT:n kautta asennetut sovellukset haitallisen toiminnan varalta."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Näytetään Bluetooth-laitteet, joilla ei ole nimiä (vain MAC-osoitteet)."</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Bluetoothin yleinen äänenvoimakkuuden säätö poistetaan käytöstä ongelmien välttämiseksi esimerkiksi silloin, kun laitteen äänenvoimakkuus on liian kova tai sitä ei voi säätää."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Salli puhelimen soittoäänten toistaminen Bluetooth-kuulokemikrofoneissa"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Paikallinen pääte"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Ota käyttöön päätesov. joka mahdollistaa paikall. liittymäkäytön"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-tarkistus"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 6fbe49a..c0c29d3 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Accélération matérielle pour le partage de connexion"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Afficher les appareils Bluetooth sans nom"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activer la signalisation intra-bande"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Version du profil Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Sélectionner la version du profil Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Les appareils Bluetooth sans nom (adresses MAC seulement) seront affichés"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Désactive la fonctionnalité de volume absolu par Bluetooth en cas de problème de volume sur les appareils à distance, par exemple si le volume est trop élevé ou s\'il ne peut pas être contrôlé."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Autoriser la lecture des sonneries du téléphone sur les écouteurs Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Activer l\'application Terminal permettant l\'accès au shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Vérification HDCP"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 10addbb..50c99e2 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Accélération matérielle pour le partage de connexion"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Afficher les appareils Bluetooth sans nom"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activer la signalisation intra-bande"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Version Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Sélectionner la version Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Les appareils Bluetooth seront affichés sans nom (adresse MAC uniquement)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Désactive la fonctionnalité de volume absolu du Bluetooth en cas de problème de volume sur les appareils à distance, par exemple si le volume est trop élevé ou s\'il ne peut pas être contrôlé."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Autoriser la lecture des sonneries du téléphone sur les casques Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Activer l\'application Terminal permettant l\'accès au shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Vérification HDCP"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 47d8408..775bbf1 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración de hardware para conexión compartida"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sen nomes"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactivar volume absoluto"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activar a función de soar na mesma banda"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión AVRCP de Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecciona a versión AVRCP de Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec de audio por Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar as aplicacións instaladas a través de ADB/ADT para detectar comportamento perigoso."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Mostraranse dispositivos Bluetooth sen nomes (só enderezos MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desactiva a función do volume absoluto do Bluetooth en caso de que se produzan problemas de volume cos dispositivos remotos, como volume demasiado alto ou falta de control."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permite que os tons de chamada do teléfono se reproduzan nos auriculares Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Activa a aplicación terminal que ofrece acceso ao shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación HDCP"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index f6bb039..712e57e 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ટિથરિંગ માટે હાર્ડવેર ગતિવૃદ્ધિ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"નામ વિનાના બ્લૂટૂથ ઉપકરણો બતાવો"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ચોક્કસ વૉલ્યૂમને અક્ષમ કરો"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"બેંડમાં રિંગ કરવાનું સક્ષમ કરો"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"બ્લૂટૂથ AVRCP સંસ્કરણ"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"બ્લૂટૂથ AVRCP સંસ્કરણ પસંદ કરો"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"બ્લૂટૂથ ઑડિઓ કોડેક"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"હાનિકારક વર્તણૂંક માટે ADB/ADT મારફતે ઇન્સ્ટોલ કરવામાં આવેલી ઍપ્લિકેશનો તપાસો."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"નામ વગરના (ફક્ત MAC ઍડ્રેસવાળા) બ્લૂટૂથ ઉપકરણો બતાવવામાં આવશે"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"રિમોટ ઉપકરણોમાં વધુ પડતું ઊંચું વૉલ્યૂમ અથવા નિયંત્રણની કમી જેવી વૉલ્યૂમની સમસ્યાઓની સ્થિતિમાં બ્લૂટૂથ ચોક્કસ વૉલ્યૂમ સુવિધાને અક્ષમ કરે છે."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ફોનની રિંગટોન બ્લૂટૂથ હૅડસેટ પર વાગવાની મંજૂરી આપો"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"સ્થાનિક ટર્મિનલ"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"સ્થાનિક શેલ અ‍ૅક્સેસની ઑફર કરતી ટર્મિનલ એપ્લિકેશનને સક્ષમ કરો"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP તપાસણી"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index fcca957..a88abb5 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"हार्डवेयर से तेज़ी लाने के लिए टेदर करें"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ब्लूटूथ से आवाज़ के नियंत्रण की सुविधा रोकें"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"इन-बैंड रिंग करना चालू करें"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ब्लूटूथ AVRCP वर्शन"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ब्लूटूथ AVRCP वर्शन चुनें"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लूटूथ ऑडियो कोडेक"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"नुकसानदेह व्यवहार के लिए ADB/ADT के द्वारा इंस्टॉल किए गए ऐप्स  जाँचें."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"बिना नाम वाले ब्लूटूथ डिवाइस (केवल MAC पते वाले) दिखाए जाएंगे"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूर के डिवाइस पर आवाज़ बहुत बढ़ जाने या उससे नियंत्रण हटने जैसी समस्याएं होने पर, यह ब्लूटूथ के ज़रिए आवाज़ के नियंत्रण की सुविधा रोक देता है."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"फ़ोन की रिंगटोन को ब्लूटूथ हेडसेट पर बजने दें"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"लोकल शेल तक पहुंचने की सुविधा देने वाले टर्मिनल ऐप को चालू करें"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP जाँच"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 514f648..a417cc1 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzanje za modemsko povezivanje"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Prikaži Bluetooth uređaje bez naziva"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući apsolutnu glasnoću"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Omogući zvuk zvona unutar pojasne širine"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Verzija AVRCP-a za Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Odaberite verziju AVRCP-a za Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek za Bluetooth Audio"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerite uzrokuju li aplikacije instalirane putem ADB-a/ADT-a poteškoće."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Prikazivat će se Bluetooth uređaji bez naziva (samo MAC adrese)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućuje Bluetoothovu značajku apsolutne glasnoće ako udaljeni uređaji imaju poteškoća sa zvukom, kao što su, primjerice, neprihvatljiva glasnoća ili nepostojanje kontrole."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Omogući reprodukciju melodija zvona telefona putem Bluetooth slušalica"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Omogući aplikaciju terminala koja nudi pristup lokalnoj ovojnici"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provjera"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9c94579..b6f1460 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Internetmegosztás hardveres gyorsítása"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Név nélküli Bluetooth-eszközök megjelenítése"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Abszolút hangerő funkció letiltása"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Sávon belüli csörgetés engedélyezése"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"A Bluetooth AVRCP-verziója"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"A Bluetooth AVRCP-verziójának kiválasztása"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth hang – Kodek"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Az ADB/ADT útján telepített alkalmazások ellenőrzése kártékony viselkedésre."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Név nélküli Bluetooth-eszközök jelennek meg (csak MAC-címekkel)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Letiltja a Bluetooth abszolút hangerő funkcióját a távoli eszközökkel kapcsolatos hangerőproblémák – például elfogadhatatlanul magas vagy nem vezérelhető hangerő – esetén."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"A telefonon lévő csengőhangok Bluetooth-headseteken való lejátszásának engedélyezése"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Helyi végpont"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Végalkalmazás engedélyezése a helyi rendszerhéj eléréséhez"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ellenőrzés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 80431a0..3ba3f45 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Սարքակազմի արագացման միացում"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Ցուցադրել Bluetooth սարքերն առանց անունների"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Անջատել ձայնի բացարձակ ուժգնությունը"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Միացնել ներխմբային զանգը"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP տարբերակը"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Ընտրել Bluetooth AVRCP տարբերակը"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth աուդիո կոդեկ"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Ստուգեք տեղադրված հավելվածը ADB/ADT-ի միջոցով կասկածելի աշխատանքի պատճառով:"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth սարքերը կցուցադրվեն առանց անունների (միայն MAC հասցեները)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Կասեցնում է Bluetooth-ի ձայնի բացարձակ ուժգնության գործառույթը՝ հեռավոր սարքերի հետ ձայնի ուժգնությանը վերաբերող խնդիրներ ունենալու դեպքում (օրինակ՝ երբ ձայնի ուժգնությունն անընդունելի է կամ դրա կառավարումը հնարավոր չէ):"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Ընձեռել հեռախոսի բոլոր զանգերանգների Bluetooth ականջակալներով նվագարկումը"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Տեղային տերմինալ"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Միացնել տերմինալային հավելվածը, որն առաջարկում է մուտք տեղային խեցի"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ստուգում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 536d22e..2bb9ae0 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Akselerasi hardware tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Tampilkan perangkat Bluetooth tanpa nama"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Nonaktifkan volume absolut"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Aktifkan dering in-band"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versi AVRCP Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Pilih Versi AVRCP Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec Audio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Periksa perilaku membahayakan dalam aplikasi yang terpasang melalui ADB/ADT."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Perangkat Bluetooth tanpa nama (hanya alamat MAC) akan ditampilkan"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Menonaktifkan fitur volume absolut Bluetooth jika ada masalah volume dengan perangkat jarak jauh, misalnya volume terlalu keras atau kurangnya kontrol."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Izinkan nada dering di ponsel diputar di headset Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal lokal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Aktifkan aplikasi terminal yang menawarkan akses kerangka lokal"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Pemeriksaan HDCP"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index a29fbe5..311227f 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Vélbúnaðarhröðun fyrir tjóðrun"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Sýna Bluetooth-tæki án heita"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Slökkva á samstillingu hljóðstyrks"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Leyfa símtöl á sömu rás"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-útgáfa"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Velja Bluetooth AVRCP-útgáfu"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth hljóðkóðari"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kanna skaðlega hegðun forrita sem sett eru upp frá ADB/ADT."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-tæki án heita (aðeins MAC-vistfang) verða birt"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Slekkur á samstillingu Bluetooth-hljóðstyrks ef vandamál koma upp með hljóðstyrk hjá fjartengdum tækjum, svo sem of hár hljóðstyrkur eða erfiðleikar við stjórnun."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Leyfa að hringitónar í símanum spilist í Bluetooth-höfuðtólum"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Staðbundin skipanalína"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Virkja skipanalínuforrit sem leyfir staðbundinn skeljaraðgang"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-athugun"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index df0157a..b63232d 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering accelerazione hardware"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostra dispositivi Bluetooth senza nome"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disattiva volume assoluto"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Attiva suoneria in banda"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versione Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Seleziona versione Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le app installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Verranno mostrati solo dispositivi Bluetooth senza nome (solo indirizzo MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Consente di disattivare la funzione del volume assoluto Bluetooth in caso di problemi con il volume dei dispositivi remoti, ad esempio un volume troppo alto o la mancanza di controllo."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Consenti la riproduzione delle suonerie del telefono tramite gli auricolari Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminale locale"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Abilita l\'app Terminale che offre l\'accesso alla shell locale"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Verifica HDCP"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 0d78f26..538da91 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"שיפור מהירות באמצעות חומרה לצורך שיתוף אינטרנט בין ניידים"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"‏הצגת מכשירי Bluetooth ללא שמות"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"השבת עוצמת קול מוחלטת"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"‏הפעל צלצולים בערוץ ה-Bluetooth‏ (in-band ringing)"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‏Bluetooth גרסה AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"‏בחר Bluetooth גרסה AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"‏Codec אודיו ל-Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏בדוק אפליקציות שהותקנו באמצעות ADB/ADT לאיתור התנהגות מזיקה."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"‏יוצגו מכשירי Bluetooth ללא שמות (כתובות MAC בלבד)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"‏משבית את תכונת עוצמת הקול המוחלטת ב-Bluetooth במקרה של בעיות בעוצמת הקול במכשירים מרוחקים, כגון עוצמת קול רמה מדי או חוסר שליטה ברמת העוצמה."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"‏הפעלת רינגטונים באוזניות Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"מסוף מקומי"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"הפעל אפליקציית מסוף המציעה גישה מקומית למעטפת"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"‏בדיקת HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 4dddcd7..db1baa1 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"テザリング時のハードウェア アクセラレーション"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bluetooth デバイスを名前なしで表示"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"絶対音量を無効にする"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"インバンド リンギングを有効にする"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP バージョン"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP バージョンを選択する"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth オーディオ コーデック"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT経由でインストールされたアプリに不正な動作がないかを確認する"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth デバイスを名前なしで(MAC アドレスのみで)表示します"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"リモート端末で音量に関する問題(音量が大きすぎる、制御できないなど)が発生した場合に、Bluetooth の絶対音量の機能を無効にする。"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"スマートフォンの着信音が Bluetooth ヘッドセットで再生されることを許可する"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"ローカルターミナル"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"ローカルシェルアクセスを提供するターミナルアプリを有効にします"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCPチェック"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index d202993..00eaf84 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ტეტერინგის აპარატურული აჩქარება"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bluetooth-მოწყობილობების ჩვენება სახელების გარეშე"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ხმის აბსოლუტური სიძლიერის გათიშვა"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ზოლსშიდა დარეკვის ჩართვა"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth-ის AVRCP-ის ვერსია"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"აირჩიეთ Bluetooth-ის AVRCP-ის ვერსია"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth აუდიოს კოდეკი"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"შეამოწმეთ, რამდენად უსაფრთხოა ADB/ADT-ის საშუალებით ინსტალირებული აპლიკაციები."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-მოწყობილობები ნაჩვენები იქნება სახელების გარეშე (მხოლოდ MAC-მისამართები)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"გათიშავს Bluetooth-ის ხმის აბსოლუტური სიძლიერის ფუნქციას დისტანციურ მოწყობილობებზე ხმასთან დაკავშირებული ისეთი პრობლემების არსებობის შემთხვევაში, როგორიცაა ხმის დაუშვებლად მაღალი სიძლიერე ან კონტროლის შეუძლებლობა."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ტელეფონის ზარების Bluetooth-ყურსაცვამებზე დაკვრის დაშვება"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"ადგილობრივი ტერმინალი"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"ლოკალურ გარსზე წვდომის ტერმინალური აპლიკაციის ჩართვა"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP შემოწმება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 9f7c166..a318bd8 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Тетерингтің аппараттық жеделдетуі"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Атаусыз Bluetooth құрылғыларын көрсету"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Абсолютті дыбыс деңгейін өшіру"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ішкі жолақтағы шылдырлауды қосу"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP нұсқасы"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP нұсқасын таңдау"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудимазмұн кодегі"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT арқылы орнатылған қолданбалардың залалды болмауын тексеру."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Атаусыз Bluetooth құрылғылары (тек MAC мекенжайымен) көрсетіледі"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Қолайсыз қатты дыбыс деңгейі немесе басқарудың болмауы сияқты қашықтағы құрылғыларда дыбыс деңгейімен мәселелер жағдайында Bluetooth абсолютті дыбыс деңгейі функциясын өшіреді."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Телефондағы қоңырау әуендерінің Bluetooth құлақаспабында ойнатылуына мүмкіндік беру"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Жергілікті терминал"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Жергілікті шелл-код қол жетімділігін ұсынатын терминалды қолданбаны қосу"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP (жоғары кең жолақты сандық мазмұнды қорғау) тексеру"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 59fca43..ae47318 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ការ​បង្កើនល្បឿន​ផ្នែករឹងសម្រាប់​ការភ្ជាប់"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"បង្ហាញ​ឧបករណ៍​ប្ល៊ូធូស​គ្មានឈ្មោះ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"បិទកម្រិតសំឡេងលឺខ្លាំង"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"បើក​ការ​រោទ៍​ក្នុងបណ្តាញ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"កំណែប្ល៊ូធូស AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ជ្រើសរើសកំណែប្ល៊ូធូស AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"កូឌិក​សំឡេង​ប៊្លូធូស"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ពិនិត្យ​កម្មវិធី​បាន​ដំឡើង​តាម​រយៈ ADB/ADT សម្រាប់​ឥរិយាបថ​ដែល​គ្រោះ​ថ្នាក់។"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"​ឧបករណ៍​ប្ល៊ូធូសគ្មានឈ្មោះ​ (អាសយដ្ឋាន MAC តែប៉ុណ្ណោះ) នឹង​បង្ហាញ"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"បិទលក្ខណៈពិសេសកម្រិតសំឡេងលឺខ្លាំងពេលភ្ជាប់ប៊្លូធូសក្នុងករណីមានបញ្ហាជាមួយឧបករណ៍បញ្ជាពីចម្ងាយ ដូចជាកម្រិតសំឡេងលឺខ្លាំងដែលមិនអាចទទួលយកបាន ឬខ្វះការគ្រប់គ្រង។"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"អនុញ្ញាត​ឲ្យ​សំឡេង​រោទ៍​នៅ​លើ​ទូរសព្ទ​បញ្ចេញសំឡេង​តាម​រយៈ​កាស​ប្ល៊ូធូស"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"ស្ថានីយ​មូលដ្ឋាន"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"បើក​កម្មវិធី​ស្ថានីយ​ដែល​ផ្ដល់​ការ​ចូល​សែល​មូលដ្ឋាន"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"ពិនិត្យ HDCP"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 5a9bfb7..fbabb62 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ಹಾರ್ಡ್‌ವೇರ್‌ನ ವೇಗವರ್ಧನೆಯನ್ನು ಟೆಥರಿಂಗ್ ಮಾಡಿ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"ಹೆಸರುಗಳಿಲ್ಲದ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ಇನ್ ಬ್ಯಾಂಡ್ ರಿಂಗಿಂಗ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿ"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿಯನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಕೋಡೆಕ್"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ಹಾನಿಮಾಡುವಂತಹ ವರ್ತನೆಗಾಗಿ ADB/ADT ಮೂಲಕ ಸ್ಥಾಪಿಸಲಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"ಹೆಸರುಗಳಿಲ್ಲದ (ಕೇವಲ MAC ವಿಳಾಸಗಳು ಮಾತ್ರ) ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ರಿಮೋಟ್ ಸಾಧನಗಳೊಂದಿಗೆ ಒಪ್ಪಲಾಗದ ಜೋರಾದ ವಾಲ್ಯೂಮ್ ಅಥವಾ ನಿಯಂತ್ರಣದ ಕೊರತೆಯಂತಹ ವಾಲ್ಯೂಮ್ ಸಮಸ್ಯೆಗಳಂತಹ ಸಂದರ್ಭದಲ್ಲಿ ಬ್ಲೂಟೂತ್ ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್ ವೈಶಿಷ್ಟ್ಯವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ಫೋನ್‌ನ ರಿಂಗ್‌ಟೋನ್‌ಗಳನ್ನು ಬ್ಲೂಟೂತ್ ಹೆಡ್‌ಸೆಟ್‌ಗಳಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಅನುಮತಿ ನೀಡಿ"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"ಸ್ಥಳೀಯ ಟರ್ಮಿನಲ್"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"ಸ್ಥಳೀಯ ಶೆಲ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸುವ ಟರ್ಮಿನಲ್ ಅಪ್ಲಿಕೇಶನ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ಪರೀಕ್ಷಿಸುವಿಕೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index c198cb6..4b7d0a4 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"테더링 하드웨어 가속"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"이름이 없는 블루투스 기기 표시"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"절대 볼륨 사용 안함"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"대역 내 벨소리 사용 설정"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"블루투스 AVRCP 버전"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"블루투스 AVRCP 버전 선택"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"블루투스 오디오 코덱"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT을 통해 설치된 앱에 유해한 동작이 있는지 확인"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"이름이 없이 MAC 주소만 있는 블루투스 기기가 표시됩니다."</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"참기 어려울 정도로 볼륨이 크거나 제어가 되지 않는 등 원격 기기에서 볼륨 문제가 발생할 경우 블루투스 절대 볼륨 기능을 사용 중지합니다."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"휴대전화의 벨소리가 블루투스 헤드셋에서 재생되도록 허용"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"로컬 터미널"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"로컬 셸 액세스를 제공하는 터미널 앱 사용"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 확인"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 0e2b8c0..98ca36a 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Тетерингдин иштешин тездетүү"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Аталышсыз Bluetooth түзмөктөрү көрсөтүлсүн"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үндүн абсолюттук деңгээли өчүрүлсүн"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Канал аралык чалууну иштетүү"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP версиясы"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP версиясын тандоо"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодек"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT аркылуу орнотулган колдонмолорду зыянкечтикке текшерүү."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Аталышсыз Bluetooth түзмөктөрү (MAC даректери менен гана) көрсөтүлөт"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Алыскы түзмөктөр өтө катуу добуш чыгарып же көзөмөлдөнбөй жатса Bluetooth \"Үндүн абсолюттук деңгээли\" функциясын өчүрөт."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Телефондогу рингтондор Bluetooth гарнитурасында ойнотулсун"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Жергиликтүү терминал"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Жергиликтүү буйрук кабыгын сунуштаган терминалга уруксат берүү"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP текшерүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 32a001b..6de2a2e 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ເປີດໃຊ້ການເລັ່ງຄວາມໄວດ້ວຍຮາດແວ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"ສະແດງອຸປະກອນ Bluetooth ທີ່ບໍ່ມີຊື່"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ປິດໃຊ້ລະດັບສຽງສົມບູນ"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ເປີດສຽງເຕືອນແບບອິນແບນ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ເວີຊັນ Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ເລືອກເວີຊັນ Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ກວດສອບແອັບຯທີ່ຕິດຕັ້ງແລ້ວຜ່ານທາງ ADB/ADT ເພື່ອກວດຫາພຶດຕິກຳທີ່ເປັນອັນຕະລາຍ."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"ຈະສະແດງອຸປະກອນ Bluetooth ທີ່ບໍ່ມີຊື່ (ທີ່ຢູ່ MAC ເທົ່ານັ້ນ)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ປິດໃຊ້ຄຸນສົມບັດລະດັບສຽງສົມບູນຂອງ Bluetooth ໃນກໍລະນີເກີດບັນຫາລະດັບສຽງສົມບູນກັບອຸປະກອນທາງໄກ ເຊັ່ນວ່າ ລະດັບສຽງດັງເກີນຍອມຮັບໄດ້ ຫຼື ຄວບຄຸມບໍ່ໄດ້."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ເປີດໃຫ້ສຽງຣິງໂທນຢູ່ໂທລະສັບດັງໃນຫູຟັງ Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal ໃນໂຕເຄື່ອງ"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"ເປີດນຳໃຊ້ແອັບຯ Terminal ທີ່ໃຫ້ການເຂົ້າເຖິງ shell ໃນໂຕເຄື່ອງໄດ້"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"ການກວດສອບ HDCP"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 0e49f5be..66fa62a 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Įrenginio kaip modemo naudojimo aparatinės įrangos spartinimas"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Rodyti „Bluetooth“ įrenginius be pavadinimų"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Išjungti didžiausią garsą"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Įgalinti diapazono skambėjimą"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"„Bluetooth“ AVRCP versija"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Pasirinkite „Bluetooth“ AVRCP versiją"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"„Bluetooth“ garso kodekas"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Patikrinkite, ar programų, įdiegtų naudojant ADB / ADT, veikimas nėra žalingas."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bus rodomi „Bluetooth“ įrenginiai be pavadinimų (tik MAC adresai)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Išjungiama „Bluetooth“ didžiausio garso funkcija, jei naudojant nuotolinio valdymo įrenginius kyla problemų dėl garso, pvz., garsas yra per didelis arba jo negalima tinkamai valdyti."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Leisti telefono skambėjimo tonus per „Bluetooth“ ausines"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Vietinis terminalas"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Įgal. terminalo progr., siūlančią prieigą prie viet. apvalkalo"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP tikrinimas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index fd9d60c..f32accd 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Paātrināta aparatūras darbība piesaistei"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Rādīt Bluetooth ierīces bez nosaukumiem"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Atspējot absolūto skaļumu"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Iespējot iekšjoslas zvanīšanu"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP versija"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Atlasiet Bluetooth AVRCP versiju"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodeks"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Pārbaudīt, vai lietotņu, kuru instalēšanai izmantots ADB/ADT, darbība nav kaitīga."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Tiks parādītas Bluetooth ierīces bez nosaukumiem (tikai MAC adreses)."</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Atspējo Bluetooth absolūtā skaļuma funkciju skaļuma problēmu gadījumiem attālajās ierīcēs, piemēram, ja ir nepieņemami liels skaļums vai nav iespējas kontrolēt skaļumu."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Atļaut tālrunī esošo zvana signālu atskaņošanu Bluetooth austiņās"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Vietējā beigu lietotne"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Iespējot beigu lietotni, kurā piedāvāta vietējā čaulas piekļuve"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP pārbaude"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 85cd020..3151f56 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардверско забрзување за врзување"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Прикажувај уреди со Bluetooth без имиња"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Оневозможете апсолутна јачина на звук"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Овозможете ѕвонење во појас"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Верзија Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Изберете верзија Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодек за аудио преку Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Провери апликации инсталирани преку ADB/ADT за штетно однесување."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Уредите со Bluetooth без имиња (само MAC-адреси) ќе се прикажуваат"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Ја оневозможува карактеристиката за апсолутна јачина на звук преку Bluetooth во случај кога ќе настанат проблеми со далечинските уреди, како на пр., неприфатливо силен звук или недоволна контрола."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Дозволи мелодиите на телефонот да се пуштаат на Bluetooth слушалките"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Локален терминал"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Овозможи апликација на терминал што овозможува локален пристап кон школка."</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Проверување HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 77b58cf..2b86e50 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ടെതറിംഗ് ഹാർഡ്‌വെയർ ത്വരിതപ്പെടുത്തൽ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"പേരില്ലാത്ത Bluetooth ഉപകരണങ്ങൾ കാണിക്കുക"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"അബ്‌സൊല്യൂട്ട് വോളിയം പ്രവർത്തനരഹിതമാക്കുക"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ഇൻ-ബാൻഡ് റിംഗുചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP പതിപ്പ്"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP പതിപ്പ് തിരഞ്ഞെടുക്കുക"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth ഓഡിയോ കോഡെക്"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"കേടാക്കുന്ന പ്രവർത്തനരീതിയുള്ള ADB/ADT വഴി ഇൻസ്റ്റാളുചെയ്‌ത അപ്ലിക്കേഷനുകൾ പരിശോധിക്കുക."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"പേരില്ലാത്ത Bluetooth ഉപകരണങ്ങൾ (MAC വിലാസങ്ങൾ മാത്രം) പ്രദർശിപ്പിക്കും"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"അസ്വീകാര്യമായ തരത്തിൽ ഉയർന്ന വോളിയമോ ശബ്ദ നിയന്ത്രണത്തിന്റെ അഭാവമോ പോലെ, വിദൂര ഉപകരണങ്ങളുമായി ബന്ധപ്പെട്ട വോളിയം പ്രശ്നങ്ങൾ ഉണ്ടാകുന്ന സാഹചര്യത്തിൽ, Bluetooth അബ്‌സൊല്യൂട്ട് വോളിയം ഫീച്ചർ പ്രവർത്തനരഹിതമാക്കുന്നു."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ഫോണിലെ റിംഗ്‌ടോണുകൾ Bluetooth ഹെഡ്‌സെറ്റുകളിൽ പ്ലേ ചെയ്യാനായി അനുവദിക്കുക"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"പ്രാദേശിക ടെർമിനൽ"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"പ്രാദേശിക ഷെൽ ആക്‌സസ് നൽകുന്ന ടെർമിനൽ അപ്ലിക്കേഷൻ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP പരിശോധന"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 3c6690c..152408a 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Модем болгох хардвер хурдасгуур"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Нэргүй Bluetooth төхөөрөмжийг харуулах"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үнэмлэхүй дууны түвшинг идэвхгүй болгох"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Сүлжээний хонхны аяыг идэвхжүүлэх"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP хувилбар"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP хувилбарыг сонгох"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодлогч"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT-р суулгасан апп-уудыг хорлонтой авиртай эсэхийг шалгах."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Нэргүй Bluetooth төхөөрөмжийг (зөвхөн MAC хаяг) харуулна"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Хэт чанга дуугаралт эсвэл муу тохиргоо зэрэг алсын зайн төхөөрөмжийн дуугаралттай холбоотой асуудлын үед Bluetooth-ийн үнэмлэхүй дууны түвшинг идэвхгүй болго."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Утасны хонхны аяыг Bluetooth чихэвчээр тоглуулахыг зөвшөөрөх"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Локал терминал"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Локал суурьт хандалт хийх боломж олгодог терминалын апп-г идэвхжүүлэх"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP шалгах"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index bb0a337..7402d29 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"टेदरिंग हार्डवेअर प्रवेग"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"नावांशिवाय ब्‍लूटूथ डिव्‍हाइस दाखवा"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"संपूर्ण आवाज अक्षम करा"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"इन-बँड रिंगिंग सक्षम करा"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ब्लूटूथ AVRCP आवृत्ती"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ब्लूटूथ AVRCP आवृत्ती निवडा"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लूटूथ ऑडिओ कोडेक"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक वर्तनासाठी ADB/ADT द्वारे इंस्टॉल अॅप्स तपासा."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"नावांशिवाय ब्‍लूटूथ डीव्‍हाइस (फक्‍त MAC पत्‍ते) दाखवले जातील"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूरस्थ डीव्हाइसमध्ये सहन न होणारा मोठा आवाज किंवा नियंत्रणचा अभाव यासारखी आवाजाची समस्या असल्यास ब्लूटूथ संपूर्ण आवाज वैशिष्ट्य अक्षम करते."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"फोनवरील रिंगटोन ब्लूटूथ हेडसेटवर वाजू द्या"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"स्थानिक टर्मिनल"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"स्थानिक शेल प्रवेश देणारा टर्मिनल अॅप सक्षम करा"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP तपासणी"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index aa94b7c..51ab84e 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Pecutan perkakasan penambatan"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Tunjukkan peranti Bluetooth tanpa nama"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Lumpuhkan kelantangan mutlak"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Dayakan dering dalam jalur"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versi AVRCP Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Pilih Versi AVRCP Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec Audio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Semak apl yang dipasang melalui ADB/ADT untuk tingkah laku yang berbahaya."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Peranti Bluetooth tanpa nama (alamat MAC sahaja) akan dipaparkan"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Lumpuhkan ciri kelantangan mutlak Bluetooth dalam kes isu kelantangan menggunakan peranti kawalan jauh seperti kelantangan yang sangat kuat atau tidak dapat mengawal."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Benarkan nada dering pada telefon dimainkan pada set kepala Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal setempat"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Dayakan apl terminal yang menawarkan akses shell tempatan"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Penyemakan HDCP"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 57f6c6f..c643c59 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ဖုန်းကို မိုဒမ်အဖြစ်အသုံးပြုမှု စက်ပစ္စည်းဖြင့် အရှိန်မြှင့်တင်ခြင်း"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"အမည်မရှိသော ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသရန်"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"သတ်မှတ်ထားသည့်ဖုန်းမြည်သံကို အသုံးပြုခြင်းအား ဖွင့်ရန်"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ဘလူးတုသ် AVRCP ဗားရှင်း"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ဘလူးတုသ် AVRCP ဗားရှင်းကို ရွေးပါ"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ဘလူးတုသ်အသံ ကိုးဒက်ခ်"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT မှတဆင့် ထည့်သွင်းသော အပလီကေးရှင်းများကို အန္တရာယ်ဖြစ်နိုင်ခြင်း ရှိမရှိ စစ်ဆေးရန်။"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"အမည်မရှိသော (MAC လိပ်စာများသာပါသော) ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသပါမည်"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ချိတ်ဆက်ထားသည့် ကိရိယာတွင် လက်မခံနိုင်လောက်အောင် ဆူညံ သို့မဟုတ် ထိန်းညှိမရနိုင်သော အသံပိုင်းပြဿနာ ရှိခဲ့လျှင် ဘလူးတုသ် ပကတိ အသံနှုန်းကို ပိတ်ပါ။"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ဖုန်းတွင်းရှိ ဖုန်းမြည်သံများကို ဘလူးတုသ် မိုက်ခွက်ပါနားကြပ်တွင် ဖွင့်ခွင့်ပြုရန်"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"လိုကယ်တာမီနယ်"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"local shell အသုံးပြုခွင့်ကမ်းလှမ်းသော တာမင်နယ်အပလီကေးရှင်းဖွင့်ပါ"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP စစ်ဆေးမှု"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 1cabc5c..0cea1a7 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Maskinvareakselerasjon for internettdeling"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Vis Bluetooth-enheter uten navn"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Slå av funksjonen for absolutt volum"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Slå på innenbåndsringing"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-versjon"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Velg Bluetooth AVRCP-versjon"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek for Bluetooth-lyd"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Sjekk apper som er installert via ADB/ADT for skadelig adferd."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-enheter uten navn (bare MAC-adresser) vises"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Slår av funksjonen for absolutt volum via Bluetooth i tilfelle det oppstår volumrelaterte problemer med eksterne enheter, for eksempel uakseptabelt høyt volum eller mangel på kontroll."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Tillater at ringelyder på telefonen spilles av på Bluetooth-hodetelefoner"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Aktiver terminalappen som gir lokal kommandolistetilgang"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontroll"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index f5f2269..d0ec0f5 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"टेदरिङको लागि हार्डवेयरको प्रवेग"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"नामकरण नगरिएका ब्लुटुथ यन्त्रहरू देखाउनुहोस्"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"निरपेक्ष आवाज असक्षम गर्नुहोस्"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"इन-ब्यान्ड घन्टी बज्ने सुविधालाई सक्षम पार्नुहोस्"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ब्लुटुथको AVRCP संस्करण"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ब्लुटुथको AVRCP संस्करण चयन गर्नुहोस्"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लुटुथ अडियोको कोडेक"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक व्यवहारको लागि ADB/ADT को माध्यमबाट स्थापित अनुप्रयोगहरूको जाँच गर्नुहोस्।"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"नामकरण नगरिएका ब्लुटुथ यन्त्रहरू (MAC ठेगाना भएका मात्र) देखाइनेछ"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"रिमोट यन्त्रहरूमा अस्वीकार्य चर्को आवाज वा नियन्त्रणमा कमी जस्ता आवाज सम्बन्धी समस्याहरूको अवस्थामा ब्लुटुथ निरपेक्ष आवाज सुविधालाई असक्षम गराउँछ।"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"उक्त फोनमा भएका रिङटोनहरूलाई ब्लुटुथका हेडसेटहरूमा प्ले गर्न दिनुहोस्"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"स्थानीय सेल पहुँच प्रदान गर्ने टर्मिनल अनुप्रयोग सक्षम गर्नुहोस्"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP जाँच गर्दै"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index fe17c1d..87d20c2 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwareversnelling voor tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bluetooth-apparaten zonder namen weergeven"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"In-band bellen inschakelen"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth-AVRCP-versie"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth-AVRCP-versie selecteren"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-audiocodec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Apps die zijn geïnstalleerd via ADB/ADT, controleren op schadelijk gedrag"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-apparaten zonder namen (alleen MAC-adressen) worden weergegeven"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Hiermee wordt de functie voor absoluut volume van Bluetooth uitgeschakeld in geval van volumeproblemen met externe apparaten, zoals een onacceptabel hoog volume of geen volumeregeling."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Toestaan dat beltonen worden afgespeeld op Bluetooth-headsets"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokale terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Terminal-app inschakelen die lokale shell-toegang biedt"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-controle"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index c791107..d870a99 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ਟੈਦਰਿੰਗ ਹਾਰਡਵੇਅਰ ਐਕਸੈੱਲਰੇਸ਼ਨ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਓ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ਪੂਰਨ ਵੌਲਿਊਮ ਨੂੰ ਅਯੋਗ ਬਣਾਓ"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ਇਨ-ਬੈਂਡ ਘੰਟੀ ਵੱਜਣ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ ਚੁਣੋ"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਕੋਡੇਕ"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ਹਾਨੀਕਾਰਕ ਵਿਵਹਾਰ ਲਈ ADB/ADT ਰਾਹੀਂ ਸਥਾਪਤ ਕੀਤੀਆਂ ਐਪਾਂ ਦੀ ਜਾਂਚ ਕਰੋ।"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਈਆਂ ਜਾਣਗੀਆਂ (ਸਿਰਫ਼ MAC ਪਤੇ)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ਰਿਮੋਟ ਡੀਵਾਈਸਾਂ ਨਾਲ ਵੌਲਿਊਮ ਸਮੱਸਿਆਵਾਂ ਜਿਵੇਂ ਕਿ ਨਾ ਪਸੰਦ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਉੱਚੀ ਵੌਲਿਊਮ ਜਾਂ ਕੰਟਰੋਲ ਦੀ ਕਮੀ ਵਰਗੀ ਹਾਲਤ ਵਿੱਚ ਬਲੂਟੁੱਥ ਪੂਰਨ ਵੌਲਿਊਮ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਅਯੋਗ ਬਣਾਉਂਦਾ ਹੈ।"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੀਆਂ ਰਿੰਗਟੋਨਾਂ ਨੂੰ ਬਲੂਟੁੱਥ ਹੈੱਡਸੈੱਟਾਂ \'ਤੇ ਚਲਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"ਸਥਾਨਕ ਟਰਮੀਨਲ"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"ਟਰਮੀਨਲ ਐਪ ਨੂੰ ਚਾਲੂ ਕਰੋ ਜੋ ਸਥਾਨਕ ਸ਼ੈਲ ਪਹੁੰਚ ਪੇਸ਼ਕਸ਼ ਕਰਦਾ ਹੈ"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ਜਾਂਚ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 3c0cf9e..7b66aa5 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Akceleracja sprzętowa tetheringu"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Pokaż urządzenia Bluetooth bez nazw"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Wyłącz głośność bezwzględną"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Włącz dzwonek w kanale dźwiękowym"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Wersja AVRCP Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Wybierz wersję AVRCP Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek dźwięku Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Sprawdź, czy aplikacje zainstalowane przez ADB/ADT nie zachowują się w szkodliwy sposób"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Zostaną wyświetlone urządzenia Bluetooth bez nazw (tylko adresy MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Wyłącza funkcję Głośność bezwzględna Bluetooth, jeśli występują problemy z urządzeniami zdalnymi, np. zbyt duża głośność lub brak kontroli."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Zezwala na odtwarzanie dzwonków telefonu w zestawach słuchawkowych Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal lokalny"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Włącz terminal, który umożliwia dostęp do powłoki lokalnej"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Sprawdzanie HDCP"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 240f850..d99097a 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -142,7 +142,7 @@
     <string name="tts_play_example_summary" msgid="8029071615047894486">"Reproduzir uma rápida demonstração da voz sintetizada"</string>
     <string name="tts_install_data_title" msgid="4264378440508149986">"Instalar dados de voz"</string>
     <string name="tts_install_data_summary" msgid="5742135732511822589">"É necessário instalar os dados de voz para a sintetização da fala"</string>
-    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Este mecanismo de síntese de fala pode coletar todo texto que será falado, inclusive dados pessoais como senhas e números de cartão de crédito. Ele é proveniente do mecanismo <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Deseja ativar o uso desse mecanismo de síntese de fala?"</string>
+    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Este mecanismo de síntese de fala pode coletar todo texto que será falado, inclusive dados pessoais como senhas e números de cartão de crédito. Ele é proveniente do mecanismo <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Quer ativar o uso desse mecanismo de síntese de fala?"</string>
     <string name="tts_engine_network_required" msgid="1190837151485314743">"Este idioma requer uma conexão de rede ativa para a conversão de texto em voz."</string>
     <string name="tts_default_sample_string" msgid="4040835213373086322">"Este é um exemplo de sintetização de voz."</string>
     <string name="tts_status_title" msgid="7268566550242584413">"Status de idioma padrão"</string>
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware de tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sem nomes"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ativar o toque em banda"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versão do Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecionar versão do Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Dispositivos Bluetooth sem nomes (somente endereços MAC) serão exibidos"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa o recurso Bluetooth de volume absoluto em caso de problemas com o volume em dispositivos remotos, como volume excessivamente alto ou falta de controle."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permitir que os toques no smartphone sejam reproduzidos em fones de ouvido Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Ativar o app terminal que oferece acesso ao shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 4852406af..8c7fbba 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware para ligação (à Internet) via telemóvel"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sem nomes"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ativar toque dentro da banda"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versão de Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecionar versão de Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar as aplicações instaladas via ADB/ADT para detetar comportamento perigoso."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"São apresentados os dispositivos Bluetooth sem nomes (apenas endereços MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa a funcionalidade de volume absoluto do Bluetooth caso existam problemas de volume com dispositivos remotos, como um volume insuportavelmente alto ou a ausência de controlo."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permitir que os toques no telemóvel sejam reproduzidos em auscultadores com microfone integrado Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Ativar aplicação terminal que oferece acesso local à shell"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 240f850..d99097a 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -142,7 +142,7 @@
     <string name="tts_play_example_summary" msgid="8029071615047894486">"Reproduzir uma rápida demonstração da voz sintetizada"</string>
     <string name="tts_install_data_title" msgid="4264378440508149986">"Instalar dados de voz"</string>
     <string name="tts_install_data_summary" msgid="5742135732511822589">"É necessário instalar os dados de voz para a sintetização da fala"</string>
-    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Este mecanismo de síntese de fala pode coletar todo texto que será falado, inclusive dados pessoais como senhas e números de cartão de crédito. Ele é proveniente do mecanismo <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Deseja ativar o uso desse mecanismo de síntese de fala?"</string>
+    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Este mecanismo de síntese de fala pode coletar todo texto que será falado, inclusive dados pessoais como senhas e números de cartão de crédito. Ele é proveniente do mecanismo <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Quer ativar o uso desse mecanismo de síntese de fala?"</string>
     <string name="tts_engine_network_required" msgid="1190837151485314743">"Este idioma requer uma conexão de rede ativa para a conversão de texto em voz."</string>
     <string name="tts_default_sample_string" msgid="4040835213373086322">"Este é um exemplo de sintetização de voz."</string>
     <string name="tts_status_title" msgid="7268566550242584413">"Status de idioma padrão"</string>
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware de tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sem nomes"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ativar o toque em banda"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versão do Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecionar versão do Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Dispositivos Bluetooth sem nomes (somente endereços MAC) serão exibidos"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa o recurso Bluetooth de volume absoluto em caso de problemas com o volume em dispositivos remotos, como volume excessivamente alto ou falta de controle."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permitir que os toques no smartphone sejam reproduzidos em fones de ouvido Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Ativar o app terminal que oferece acesso ao shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 73869d50..1c67550 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Accelerare hardware pentru tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Afișați dispozitivele Bluetooth fără nume"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Dezactivați volumul absolut"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activați soneria în căști"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versiunea AVRCP pentru Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selectați versiunea AVRCP pentru Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificați aplicațiile instalate utilizând ADB/ADT, pentru a detecta un comportament dăunător."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Vor fi afișate dispozitivele Bluetooth fără nume (numai adresele MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Dezactivează funcția Bluetooth de volum absolut în cazul problemelor de volum apărute la dispozitivele la distanță, cum ar fi volumul mult prea ridicat sau lipsa de control asupra acestuia."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permiteți ca tonurile de sonerie de pe telefon să fie redate prin căștile Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Aplicație terminal locală"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Activați aplicația terminal care oferă acces la shell local"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Verificare HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 0ebf020..4b11594 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Аппаратное ускорение в режиме модема"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Показывать Bluetooth-устройства без названий"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Отключить абсолютный уровень громкости"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Включить внутриполосное воспроизведение"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Версия Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Выберите версию Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Аудиокодек для передачи через Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Выполнять проверку безопасности приложений при установке через ADB/ADT"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Показывать Bluetooth-устройства без названий (только с MAC-адресами)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Отключить абсолютный уровень громкости Bluetooth при возникновении проблем на удаленных устройствах, например при слишком громком звучании или невозможности контролировать настройку."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Разрешить воспроизведение рингтонов на телефоне через Bluetooth-гарнитуру"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Локальный терминальный доступ"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Разрешить терминальный доступ к локальной оболочке"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Проверка HDCP"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 35631c9..2ffe814d 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ටෙදරින් දෘඪාංග ත්වරණය"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"නම් නොමැති බ්ලූටූත් උපාංග පෙන්වන්න"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"නිරපේක්ෂ හඩ පරිමාව අබල කරන්න"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"කලාපය තුළ නාද වීම සබල කරන්න"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"බ්ලූටූත් AVRCP අනුවාදය"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"බ්ලූටූත් AVRCP අනුවාදය තෝරන්න"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"බ්ලූටූත් ශ්‍රව්‍ය Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT හරහා ස්ථාපනය වූ යෙදුම්, විනාශකාරී ක්‍රියාවන් ඇත්දැයි පරික්ෂාකර බලන්න."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"නම් නොමැති බ්ලූටූත් උපාංග (MAC ලිපින පමණි) සංදර්ශනය කරනු ඇත"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"පිළිගත නොහැකි ලෙස වැඩි හඩ පරිමාව හෝ පාලනය නොමැති වීම යනාදී දුරස්ථ උපාංග සමගින් වන හඬ පරිමා ගැටලුවලදී බ්ලූටූත් නිරපේක්ෂ හඬ පරිමා විශේෂාංගය අබල කරයි."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"දුරකථනයේ නාද රටාවලට බ්ලූටූත් මත වාදනය වීමට ඉඩ දෙන්න"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"අභ්‍යන්තර අන්තය"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"දේශීය ෂෙල් ප්‍රවේශනය පිරිනමන ටර්මිනල් යෙදුම සබල කරන්න"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP පරික්ෂාව"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index c90e221..0cefd71 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardvérovú akcelerácia pre tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Zobrazovať zariadenia Bluetooth bez názvov"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zakázať absolútnu hlasitosť"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Povoliť zvonenie v hovorovom pásme"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Verzia rozhrania Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Zvoľte verziu rozhrania Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio – kodek"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolovať škodlivosť aplikácií nainštalovaných pomocou nástroja ADB alebo ADT"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Zariadenia Bluetooth sa budú zobrazovať bez názvov (iba adresy MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Umožňuje zakázať funkciu absolútnej hlasitosti rozhrania Bluetooth v prípade problémov s hlasitosťou na vzdialených zariadeniach, ako je napríklad neprijateľne vysoká hlasitosť alebo absencia ovládacích prvkov."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Umožňuje prehrávať tóny zvonenia na telefóne v náhlavných súpravách Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Miestny terminál"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Povoliť terminálovú apl. na miestny prístup k prostrediu shell"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrola HDCP"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index a131632..0864d5b 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Naprave Bluetooth prikaži brez imen"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogočanje absolutnega praga glasnosti"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Omogoči zvonjenje iz telefona"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Različica profila AVRCP za Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Izberite različico profila AVRCP za Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Zvočni kodek za Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Preveri, ali so aplikacije, nameščene prek ADB/ADT, škodljive."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Naprave Bluetooth bodo prikazane brez imen (samo z naslovi MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogoči funkcijo absolutnega praga glasnosti za Bluetooth, če pride do težav z glasnostjo z oddaljenimi napravami, kot je nesprejemljivo visoka glasnost ali pomanjkanje nadzora."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Omogoči, da se toni zvonjenja v telefonu predvajajo v slušalkah z mikrofonom Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Omogočanje terminalske aplikacije za dostop do lokalne lupine"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Preverjanje HDCP"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index d5e92dc..63da6ff 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Përshpejtimi i harduerit për ndarjen"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Shfaq pajisjet me Bluetooth pa emra"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Çaktivizo volumin absolut"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Aktivizo zilen brenda të njëjtit brez"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versioni AVRCP i Bluetooth-it"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Zgjidh versionin AVRCP të Bluetooth-it"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodeku Bluetooth Audio"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollo aplikacionet e instaluara nëpërmjet ADB/ADT për sjellje të dëmshme."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Pajisjet me Bluetooth do të shfaqen pa emra (vetëm adresat MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Çaktivizon funksionin e volumit absolut të Bluetooth në rast të problemeve të volumit me pajisjet në largësi, si p.sh. një volum i lartë i papranueshëm ose mungesa e kontrollit."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Lejo që zilet në telefon të luhen në kufjet me \"Bluetooth\""</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminali lokal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Aktivizo aplikacionin terminal që ofron qasje në guaskën lokale"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrolli HDCP"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 94a1738..4c7aed8 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардверско убрзање привезивања"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Прикажи Bluetooth уређаје без назива"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Онемогући главно подешавање јачине звука"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Омогућавање звоњаве на истом каналу"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Верзија Bluetooth AVRCP-а"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Изаберите верзију Bluetooth AVRCP-а"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодек"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверава да ли су апликације инсталиране преко ADB-а/ADT-а штетне."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Биће приказани Bluetooth уређаји без назива (само са MAC адресама)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Онемогућава главно подешавање јачине звука на Bluetooth уређају у случају проблема са јачином звука на даљинским уређајима, као што су изузетно велика јачина звука или недостатак контроле."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Омогућите да се мелодија звона на телефону пушта преко Bluetooth слушалица"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Локални терминал"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Омогући аплик. терминала за приступ локалном командном окружењу"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP провера"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 5a7dca3..e44dcd8 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Maskinvaruacceleration för internetdelning"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Visa namnlösa Bluetooth-enheter"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inaktivera Absolute volume"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Aktivera samtal inom nätverket"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"AVRCP-version för Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Välj AVRCP-version för Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Ljudkodek för Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollera om appar som installeras via ADB/ADT kan vara skadliga."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-enheter utan namn (enbart MAC-adresser) visas"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inaktivera Bluetooth-funktionen Absolute volume om det skulle uppstå problem med volymen på fjärrenheter, t.ex. alldeles för hög volym eller brist på kontroll."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Tillåt att ringsignaler på mobilen kan spelas upp i Bluetooth-headset"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Aktivera en terminalapp som ger åtkomst till hyllor lokalt"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontroll"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 01db36a..66cfda8 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Kuongeza kasi kwa kutumia maunzi ili kusambaza mtandao"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Onyesha vifaa vya Bluetooth visivyo na majina"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zima sauti kamili"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Washa kipengele cha mlio wa simu katika kituo hicho hicho"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Toleo la Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Chagua Toleo la Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodeki ya Sauti ya Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kagua programu zilizosakinishwa kupitia ADB/ADT kwa tabia ya kudhuru."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Itaonyesha vifaa vya Bluetooth bila majina (anwani za MAC pekee)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Huzima kipengele cha Bluetooth cha sauti kamili kunapotokea matatizo ya sauti katika vifaa vya mbali kama vile sauti ya juu mno au inaposhindikana kuidhibiti."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Ruhusu milio ya simu kwenye simu ichezwe kwenye Vifaa vya sauti vya Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Kituo cha karibu"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Washa programu ya mwisho inayotoa ufikiaji mkuu wa karibu"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Inakagua HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 71dcd0f..dd218c6 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"வன்பொருள் விரைவுப்படுத்துதல் இணைப்பு முறை"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"பெயர்கள் இல்லாத புளூடூத் சாதனங்களைக் காட்டு"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"இன்-பேண்ட் ரிங் செய்வதை இயக்கு"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"புளூடூத் AVRCP பதிப்பு"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"புளூடூத் AVRCP பதிப்பைத் தேர்ந்தெடு"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"புளூடூத் ஆடியோ கோடெக்"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"தீங்கு விளைவிக்கும் செயல்பாட்டை அறிய ADB/ADT மூலம் நிறுவப்பட்டப் பயன்பாடுகளைச் சரிபார்."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"பெயர்கள் இல்லாத புளூடூத் சாதனங்கள் (MAC முகவரிகள் மட்டும்) காட்டப்படும்"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"மிகவும் அதிகமான ஒலியளவு அல்லது கட்டுப்பாடு இழப்பு போன்ற தொலைநிலைச் சாதனங்களில் ஏற்படும் ஒலி தொடர்பான சிக்கல்கள் இருக்கும் சமயங்களில், புளூடூத் அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கும்."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ஃபோனில் இருக்கும் ரிங்டோன்களை, புளூடூத் ஹெட்செட்களில் இயக்க அனுமதி"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"அக முனையம்"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"அக ஷெல் அணுகலை வழங்கும் இறுதிப் பயன்பாட்டை இயக்கு"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP சரிபார்ப்பு"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 7db8e0d..b21eb8c 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"టెథెరింగ్ హార్డ్‌వేర్ వేగవృద్ధి"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"పేర్లు లేని బ్లూటూత్ పరికరాలు  చూపించు"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"సంపూర్ణ వాల్యూమ్‌‍ను నిలిపివేయి"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ఇన్-బ్యాండ్ రింగింగ్‌ని ప్రారంభించండి"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"బ్లూటూత్ AVRCP వెర్షన్"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"బ్లూటూత్ AVRCP సంస్కరణను ఎంచుకోండి"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"బ్లూటూత్ ఆడియో కోడెక్"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"హానికరమైన ప్రవర్తన కోసం ADB/ADT ద్వారా ఇన్‌స్టాల్ చేయబడిన అనువర్తనాలను తనిఖీ చేయి."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"పేర్లు (MAC చిరునామాలు మాత్రమే) లేని బ్లూటూత్ పరికరాలు ప్రదర్శించబడతాయి"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"రిమోట్ పరికరాల్లో ఆమోదించలేని స్థాయిలో అధిక వాల్యూమ్ ఉండటం లేదా వాల్యూమ్ నియంత్రణ లేకపోవడం వంటి సమస్యలు ఉంటే బ్లూటూత్ సంపూర్ణ వాల్యూమ్ లక్షణాన్ని నిలిపివేస్తుంది."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"బ్లూటూత్ హెడ్‌సెట్‌లలో ప్లే చేయడానికి ఫోన్‌లో రింగ్‌టోన్‌లను అనుమతించండి"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"స్థానిక టెర్మినల్"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"స్థానిక షెల్ ప్రాప్యతను అందించే టెర్మినల్ అనువర్తనాన్ని ప్రారంభించు"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP తనిఖీ"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index f2f1c90..447b188 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"การเร่งฮาร์ดแวร์การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"แสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ปิดใช้การควบคุมระดับเสียงของอุปกรณ์อื่น"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"เปิดใช้การส่งเสียงในช่องสัญญาณเดียวกัน"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"เวอร์ชันของบลูทูธ AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"เลือกเวอร์ชันของบลูทูธ AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ตัวแปลงรหัสเสียงบลูทูธ"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ตรวจสอบแอปพลิเคชันที่ติดตั้งผ่าน ADB/ADT เพื่อตรวจดูพฤติกรรมที่เป็นอันตราย"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"ระบบจะแสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ (มีเฉพาะที่อยู่ MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ปิดใช้ฟีเจอร์การควบคุมระดับเสียงของอุปกรณ์อื่นผ่านบลูทูธในกรณีที่มีปัญหาเกี่ยวกับระดับเสียงของอุปกรณ์ระยะไกล เช่น ระดับเสียงที่ดังเกินไปหรือระดับเสียงที่ไม่มีการควบคุม"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ให้เสียงเรียกเข้าในโทรศัพท์เล่นในชุดหูฟังบลูทูธ"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"เทอร์มินัลในตัวเครื่อง"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"เปิดใช้งานแอปเทอร์มินัลที่ให้การเข้าถึงเชลล์ในตัวเครื่อง"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"การตรวจสอบ HDCP"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 871c384..a5e0b89 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardware acceleration para sa pag-tether"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Ipakita ang mga Bluetooth device na walang pangalan"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"I-disable ang absolute volume"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"I-enable ang pag-ring na nasa band"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bersyon ng AVRCP ng Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Pumili ng Bersyon ng AVRCP ng Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tingnan kung may nakakahamak na pagkilos sa apps na na-install sa pamamagitan ng ADB/ADT."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Ipapakita ang mga Bluetooth device na walang pangalan (mga MAC address lang)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Dini-disable ang absolute volume feature ng Bluetooth kung may mga isyu sa volume ang mga malayong device gaya ng hindi katanggap-tanggap na malakas na volume o kawalan ng kontrol."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Payagan ang pag-play ng mga ringtone sa telepono sa mga headset na gumagamit ng Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokal na terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Paganahin ang terminal app na nag-aalok ng lokal na shell access"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Pagsusuring HDCP"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 7b98d58..e6bba5b 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering donanım hızlandırıcısı"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Adsız Bluetooth cihazlarını göster"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Mutlak sesi iptal et"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Bant içi zil çaldırmayı etkinleştir"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Sürümü"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP Sürümünü seçin"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Ses Codec\'i"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT üzerinden yüklenen uygulamaları zararlı davranışlara karşı denetle."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Adsız Bluetooth cihazları (yalnızca MAC adresleri) gösterilecek"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Uzak cihazda sesin aşırı yüksek olması veya kontrol edilememesi gibi ses sorunları olması ihtimaline karşı Bluetooh mutlak ses özelliğini iptal eder."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Telefondaki zil seslerinin Bluetooth kulaklıklarda çalınmasına olanak tanır"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Yerel terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Yerel kabuk erişimi sunan terminal uygulamasını etkinleştir"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP denetimi"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 9514b2b..65f39ed 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Апаратне прискорення під час використання телефона в режимі модема"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Показувати пристрої Bluetooth без назв"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Вимкнути абсолютну гучність"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Увімкнути внутрішньосмугові сигнали"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Версія Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Виберіть версію Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодек для аудіо Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Перевіряти безпеку додатків, установлених через ADB/ADT."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Пристрої Bluetooth відображатимуться без назв (лише MAC-адреси)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Функція абсолютної гучності Bluetooth вимикається, якщо на віддалених пристроях виникають проблеми, як-от надто висока гучність або втрата контролю."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Дозволити відтворювати сигнали дзвінка на телефоні через гарнітуру Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Локальний термінал"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Увімк. програму-термінал, що надає локальний доступ до оболонки"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Перевірка HDCP"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index a344c65..7830bb8 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"ٹیدرنگ ہارڈویئر سرعت کاری"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"مطلق والیوم کو غیر فعال کریں"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ان بینڈ رنگنگ فعال کریں"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‏بلوٹوتھ AVRCP ورژن"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"‏بلوٹوتھ AVRCP ورژن منتخب کریں"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"بلوٹوتھ آڈیو کوڈیک"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏نقصان دہ رویے کے مدنظر ADB/ADT کی معرفت انسٹال شدہ ایپس کی جانچ کریں۔"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"‏بغیر نام والے بلوٹوتھ آلات (صرف MAC پتے) ڈسپلے کئے جائیں گے"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ریموٹ آلات کے ساتھ والیوم کے مسائل مثلاً نا قابل قبول حد تک بلند والیوم یا کنٹرول نہ ہونے کی صورت میں بلو ٹوتھ مطلق والیوم والی خصوصیت کو غیر فعال کریں۔"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"فون پر موجود رنگ ٹونز کو بلوٹوتھ ہیڈ سیٹز پر چلنے دیں"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"مقامی ٹرمینل"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"مقامی شیل رسائی پیش کرنے والی ٹرمینل ایپ فعال کریں"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"‏HDCP چیکنگ"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index b222caf..acaaaf1 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Modem rejimida apparatli tezlashtirish"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bluetooth qurilmalarini nomlarisiz ko‘rsatish"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Ovoz balangligining mutlaq darajasini o‘chirib qo‘yish"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Bitta liniyada jiringlashni yoqish"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP versiyasi"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP versiyasini tanlang"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodeki"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT orqali o‘rnatilgan ilovalar xavfsizligini tekshiring"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth qurilmalari nomsiz (faqat MAC manzillari) ko‘rsatiladi"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Masofadan ulanadigan qurilmalar bilan muammolar yuz berganda, jumladan, juda baland ovoz yoki sozlamalarni boshqarib bo‘lmaydigan holatlarda Bluetooth ovozi balandligining mutlaq darajasini o‘chirib qo‘yadi."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Bluetooth quloqliklarda ijro etish uchun telefonda ringtonlarga ruxsat bering"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Mahalliy terminal"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Mahalliy terminalga kirishga ruxsat beruvchi terminal ilovani faollashtirish"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP tekshiruvi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 64fbd93..7732b54 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tăng tốc phần cứng cho chia sẻ kết nối"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Hiển thị các thiết bị Bluetooth không có tên"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Vô hiệu hóa âm lượng tuyệt đối"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Bật đổ chuông trong dải"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth phiên bản AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Chọn Bluetooth phiên bản AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec âm thanh Bluetooth"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kiểm tra các ứng dụng được cài đặt qua ADB/ADT để xem có hoạt động gây hại hay không."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Các thiết bị Bluetooth không có tên (chỉ có địa chỉ MAC) sẽ được hiển thị"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Vô hiệu hóa tính năng âm lượng tuyệt đối qua Bluetooth trong trường hợp xảy ra sự cố về âm lượng với các thiết bị từ xa, chẳng hạn như âm lượng lớn không thể chấp nhận được hoặc thiếu kiểm soát."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Cho phép nhạc chuông trên điện thoại được phát trên tai nghe Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Dòng lệnh cục bộ"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Bật ứng dụng dòng lệnh cung cấp quyền truy cập vỏ cục bộ"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Kiểm tra HDCP"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 8029727..f036eae 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"网络共享硬件加速"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"显示没有名称的蓝牙设备"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用绝对音量功能"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"启用手机默认铃声"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"蓝牙 AVRCP 版本"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"选择蓝牙 AVRCP 版本"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"蓝牙音频编解码器"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"通过 ADB/ADT 检查安装的应用是否存在有害行为。"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"系统将显示没有名称(只有 MAC 地址)的蓝牙设备"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"停用蓝牙绝对音量功能,即可避免在连接到远程设备时出现音量问题(例如音量高得让人无法接受或无法控制音量等)。"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"允许手机铃声通过蓝牙耳机播放"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"本地终端"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"启用终端应用,以便在本地访问 Shell"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 检查"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index dcec71f..d57a8fd 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"網絡共享硬件加速"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"顯示沒有名稱的藍牙裝置"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"啟用頻內鈴聲"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"藍牙 AVRCP 版本"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"選擇藍牙 AVRCP 版本"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"藍牙音訊編解碼器"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"透過 ADB/ADT 檢查安裝的應用程式有否有害的行為。"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"系統將顯示沒有名稱 (只有 MAC 位址) 的藍牙裝置"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"連線至遠端裝置時,如發生音量過大或無法控制音量等問題,請停用藍牙絕對音量功能。"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"允許藍牙耳機播放手機鈴聲"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"本機終端機"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"啟用可提供本機命令介面存取權的終端機應用程式"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 檢查"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 28def2d..5a329fa 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"數據連線硬體加速"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"顯示沒有名稱的藍牙裝置"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"啟用藍牙同步鈴聲功能"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"藍牙 AVRCP 版本"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"選取藍牙 AVRCP 版本"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"藍牙音訊轉碼器"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"檢查透過 ADB/ADT 安裝的應用程式是否具有有害行為。"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"系統會顯示沒有名稱 (僅具有 MAC 位址) 的藍牙裝置"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"只要停用藍牙絕對音量功能,即可避免在連線到遠端裝置時,發生音量過大或無法控制音量等問題。"</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"允許手機鈴聲透過藍牙耳機播放"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"本機終端機"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"啟用可提供本機命令介面存取權的終端機應用程式"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 檢查"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 337bd57..3649ba2 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -202,7 +202,6 @@
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"I-Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bonisa amadivayisi e-Bluetooth ngaphandle kwamagama"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Khubaza ivolumu ngokuphelele"</string>
-    <string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Nika amandla ukukhala okuphakathi nomkhiqizo"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Inguqulo ye-Bluetooth ye-AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Khetha inguqulo ye-Bluetooth AVRCP"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"I-Bluetooth Audio Codec"</string>
@@ -248,7 +247,6 @@
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Hlola izinhlelo zokusebenza ezifakiwe nge-ADB/ADT ngokuziphatha okuyingozi."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Amadivayisi e-Bluetooth anganawo amagama (Amakheli e-MAC kuphela) azoboniswa"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Ikhubaza isici esiphelele sevolumu ye-Bluetooth uma kuba nezinkinga zevolumu ngamadivayisi esilawuli kude ezifana nevolumu ephezulu noma eshoda ngokulawuleka."</string>
-    <string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Vumela amathoni okukhala efonini ukuthi adlalwe kuma-earphone e-Bluetooth"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Itheminali yasendaweni"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Nika amandla uhlelo lokusebenza letheminali olunikeza ukufinyelela kwasendaweni kwe-shell"</string>
     <string name="hdcp_checking_title" msgid="8605478913544273282">"Ihlola i-HDCP"</string>
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index 02a4973..7cf7163 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -49,7 +49,7 @@
 
 LOCAL_JAVA_LIBRARIES := \
     junit \
-    platform-robolectric-3.5.1-prebuilt
+    platform-robolectric-3.6.1-prebuilt
 
 LOCAL_INSTRUMENTATION_FOR := SettingsLibShell
 LOCAL_MODULE := SettingsLibRoboTests
@@ -74,4 +74,4 @@
 
 LOCAL_ROBOTEST_TIMEOUT := 36000
 
-include prebuilts/misc/common/robolectric/3.5.1/run_robotests.mk
+include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index adb4832..ae24c07 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -16,9 +16,9 @@
 package com.android.settingslib.core.lifecycle;
 
 import static android.arch.lifecycle.Lifecycle.Event.ON_START;
-
 import static com.google.common.truth.Truth.assertThat;
 
+import android.arch.lifecycle.LifecycleOwner;
 import android.content.Context;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -48,6 +48,7 @@
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class LifecycleTest {
 
+    private LifecycleOwner mLifecycleOwner;
     private Lifecycle mLifecycle;
 
     public static class TestDialogFragment extends ObservableDialogFragment {
@@ -146,7 +147,8 @@
 
     @Before
     public void setUp() {
-        mLifecycle = new Lifecycle(() -> mLifecycle);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
index 5d5733e4..050877d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
@@ -17,11 +17,11 @@
 package com.android.settingslib.development;
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
+import android.arch.lifecycle.LifecycleOwner;
 import android.os.SystemProperties;
 import android.support.v7.preference.ListPreference;
 import android.support.v7.preference.Preference;
@@ -44,6 +44,7 @@
         shadows = SystemPropertiesTestImpl.class)
 public class LogpersistPreferenceControllerTest {
 
+    private LifecycleOwner mLifecycleOwner;
     private Lifecycle mLifecycle;
 
     @Mock
@@ -57,7 +58,8 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         SystemProperties.set("ro.debuggable", "1");
-        mLifecycle = new Lifecycle(() -> mLifecycle);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
         mController = new AbstractLogpersistPreferenceController(RuntimeEnvironment.application,
                 mLifecycle) {
             @Override
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
index 75b6c5f..88c57b5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
@@ -17,13 +17,13 @@
 package com.android.settingslib.widget;
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.arch.lifecycle.LifecycleOwner;
 import android.support.v14.preference.PreferenceFragment;
 import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceScreen;
@@ -49,13 +49,15 @@
     @Mock
     private PreferenceScreen mScreen;
 
+    private LifecycleOwner mLifecycleOwner;
     private Lifecycle mLifecycle;
     private FooterPreferenceMixin mMixin;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mLifecycle = new Lifecycle(() -> mLifecycle);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
         when(mFragment.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
         when(mFragment.getPreferenceManager().getContext())
                 .thenReturn(ShadowApplication.getInstance().getApplicationContext());
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1be0645..48a3a30 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -28,7 +28,7 @@
     <string name="def_bluetooth_disabled_profiles" translatable="false">0</string>
     <bool name="def_auto_time">true</bool>
     <bool name="def_auto_time_zone">true</bool>
-    <bool name="def_accelerometer_rotation">true</bool>
+    <bool name="def_accelerometer_rotation">false</bool>
     <!-- Default screen brightness, from 0 to 255.  102 is 40%. -->
     <integer name="def_screen_brightness">102</integer>
     <bool name="def_screen_brightness_automatic_mode">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 48de1c9..3698132 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1119,6 +1119,9 @@
         dumpSetting(s, p,
                 Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
                 GlobalSettingsProto.NOTIFICATION_SNOOZE_OPTIONS);
+        dumpSetting(s, p,
+                    Settings.Global.ZRAM_ENABLED,
+                    GlobalSettingsProto.ZRAM_ENABLED);
     }
 
     /** Dump a single {@link SettingsState.Setting} to a proto buf */
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1167d69..175cff6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1584,6 +1584,11 @@
                 restriction = UserManager.DISALLOW_SAFE_BOOT;
                 break;
 
+            case Settings.Global.AIRPLANE_MODE_ON:
+                if ("0".equals(value)) return false;
+                restriction = UserManager.DISALLOW_AIRPLANE_MODE;
+                break;
+
             default:
                 if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) {
                     if ("0".equals(value)) return false;
@@ -2940,7 +2945,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 150;
+            private static final int SETTINGS_VERSION = 151;
 
             private final int mUserId;
 
@@ -3533,6 +3538,18 @@
                     currentVersion = 150;
                 }
 
+                if (currentVersion == 150) {
+                    // Version 151: Reset rotate locked setting for upgrading users
+                    final SettingsState systemSettings = getSystemSettingsLocked(userId);
+                    systemSettings.insertSettingLocked(
+                            Settings.System.ACCELEROMETER_ROTATION,
+                            getContext().getResources().getBoolean(
+                                    R.bool.def_accelerometer_rotation) ? "1" : "0",
+                            null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+
+                    currentVersion = 151;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b3d6357..0f43db0 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -134,6 +134,7 @@
     <!-- Permission needed to access privileged VR APIs -->
     <uses-permission android:name="android.permission.RESTRICTED_VR_ACCESS" />
     <uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE" />
+    <uses-permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS" />
 
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index a8b184c..600f0dc 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -616,7 +616,7 @@
         final IWindowManager wm = IWindowManager.Stub
                 .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
         try {
-            wm.dismissKeyguard(null);
+            wm.dismissKeyguard(null, null);
         } catch (Exception e) {
             // ignore it
         }
@@ -1909,7 +1909,7 @@
             }
             final IDumpstate dumpstate = IDumpstate.Stub.asInterface(service);
             try {
-                token = dumpstate.setListener("Shell", this);
+                token = dumpstate.setListener("Shell", this, /* perSectionDetails= */ false);
                 if (token != null) {
                     token.asBinder().linkToDeath(this, 0);
                 }
@@ -1978,6 +1978,15 @@
             info.realMax = maxProgress;
         }
 
+        @Override
+        public void onSectionComplete(String title, int status, int size, int durationMs)
+                throws RemoteException {
+            if (DEBUG) {
+                Log.v(TAG, "Title: " + title + " Status: " + status + " Size: " + size
+                        + " Duration: " + durationMs + "ms");
+            }
+        }
+
         public void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("token: "); pw.println(token);
         }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
index 56a3ee3..e25930c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
@@ -50,5 +50,7 @@
         }
 
         void setDarkIntensity(float intensity);
+
+        void setDelayTouchFeedback(boolean shouldDelay);
     }
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
index 674ed5a..6131acc 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.plugins.statusbar.phone;
 
+import android.graphics.Canvas;
 import android.view.MotionEvent;
 
 import com.android.systemui.plugins.Plugin;
@@ -35,6 +36,12 @@
 
         public void setBarState(boolean vertical, boolean isRtl);
 
+        public void onDraw(Canvas canvas);
+
+        public void onDarkIntensityChange(float intensity);
+
+        public void onLayout(boolean changed, int left, int top, int right, int bottom);
+
         public default void destroy() { }
     }
 
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index c97cfc4..9adb550 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -34,7 +34,6 @@
         android:orientation="vertical">
         <RelativeLayout
             android:id="@+id/keyguard_clock_container"
-            android:animateLayoutChanges="true"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal|top">
@@ -51,16 +50,6 @@
                 android:format12Hour="@string/keyguard_widget_12_hours_format"
                 android:format24Hour="@string/keyguard_widget_24_hours_format"
                 android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
-            <com.android.systemui.ChargingView
-                android:id="@+id/battery_doze"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignTop="@id/clock_view"
-                android:layout_alignBottom="@id/clock_view"
-                android:layout_toEndOf="@id/clock_view"
-                android:visibility="invisible"
-                android:src="@drawable/ic_aod_charging_24dp"
-                android:contentDescription="@string/accessibility_ambient_display_charging" />
             <View
                 android:id="@+id/clock_separator"
                 android:layout_width="16dp"
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 7027d6f..b3ed8f5 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -101,7 +101,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"‏رمز \"رقم التعريف الشخصي\" لشريحة SIM غير صحيح، ويلزمك الاتصال الآن بمشغّل شبكة الجوّال لإلغاء قفل الجهاز."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
-      <item quantity="zero">‏رمز رقم التعريف الشخصي لشريحة SIM غير صحيح، ولم تتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
+      <item quantity="zero">‏رمز رقم التعريف الشخصي لشريحة SIM غير صحيح، ولم تتبق لديك أي محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
       <item quantity="two">‏رمز رقم التعريف الشخصي لشريحة SIM غير صحيح، ويتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
       <item quantity="few">‏رمز رقم التعريف الشخصي لشريحة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات.</item>
       <item quantity="many">‏رمز رقم التعريف الشخصي لشريحة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة.</item>
@@ -110,7 +110,7 @@
     </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"‏شريحة SIM غير صالحة للاستخدام. يُرجى الاتصال بمشغّل شبكة الجوّال."</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
-      <item quantity="zero">‏رمز PUK لشريحة SIM غير صحيح، ولم تتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
+      <item quantity="zero">‏رمز PUK لشريحة SIM غير صحيح، ولم تتبق لديك أي محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
       <item quantity="two">‏رمز PUK لشريحة SIM غير صحيح، ويتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>) تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
       <item quantity="few">‏رمز PUK لشريحة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
       <item quantity="many">‏رمز PUK لشريحة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index b74a618..1f6addf 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -147,8 +147,8 @@
       <item quantity="other">Unesite PIN kôd za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
     </plurals>
     <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
-      <item quantity="one">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaj prije nego što SIM kartica postane trajno neupotrebljiva. Obratite se operateru za više informacija.</item>
-      <item quantity="few">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Obratite se operateru za više informacija.</item>
-      <item quantity="other">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Obratite se operateru za više informacija.</item>
+      <item quantity="one">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaj prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item>
+      <item quantity="few">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item>
+      <item quantity="other">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item>
     </plurals>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index e511940..b6dc72b 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -135,4 +135,12 @@
       <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
     </plurals>
     <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognised"</string>
+    <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+      <item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
+      <item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
+    </plurals>
+    <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+      <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
+      <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
+    </plurals>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index e511940..b6dc72b 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -135,4 +135,12 @@
       <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
     </plurals>
     <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognised"</string>
+    <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+      <item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
+      <item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
+    </plurals>
+    <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+      <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
+      <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
+    </plurals>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index e511940..b6dc72b 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -135,4 +135,12 @@
       <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
     </plurals>
     <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognised"</string>
+    <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+      <item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
+      <item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
+    </plurals>
+    <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+      <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
+      <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
+    </plurals>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index e511940..b6dc72b 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -135,4 +135,12 @@
       <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm password.</item>
     </plurals>
     <string name="fingerprint_not_recognized" msgid="348813995267914625">"Not recognised"</string>
+    <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+      <item quantity="other">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
+      <item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
+    </plurals>
+    <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+      <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
+      <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
+    </plurals>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index dede142..97d16c6 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -135,4 +135,12 @@
       <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‎Device hasn\'t been unlocked for ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%d</xliff:g>‎‏‎‎‏‏‏‎ hour. Confirm password.‎‏‎‎‏‎</item>
     </plurals>
     <string name="fingerprint_not_recognized" msgid="348813995267914625">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‎Not recognized‎‏‎‎‏‎"</string>
+    <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎Enter SIM PIN, you have ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempts.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎Enter SIM PIN, you have ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempt before you must contact your carrier to unlock your device.‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎SIM is now disabled. Enter PUK code to continue. You have ‎‏‎‎‏‏‎<xliff:g id="_NUMBER_1">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempts before SIM becomes permanently unusable. Contact carrier for details.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎SIM is now disabled. Enter PUK code to continue. You have ‎‏‎‎‏‏‎<xliff:g id="_NUMBER_0">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempt before SIM becomes permanently unusable. Contact carrier for details.‎‏‎‎‏‎</item>
+    </plurals>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 001f90c..813377a 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -140,7 +140,7 @@
       <item quantity="one">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
     </plurals>
     <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
-      <item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Contatta l\'operatore per avere informazioni dettagliate.</item>
-      <item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Contatta l\'operatore per avere informazioni dettagliate.</item>
+      <item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
+      <item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
     </plurals>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 6534fbb..fb85589 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -136,11 +136,11 @@
     </plurals>
     <string name="fingerprint_not_recognized" msgid="348813995267914625">"မသိပါ"</string>
     <plurals name="kg_password_default_pin_message" formatted="false" msgid="6203676909479972943">
-      <item quantity="other">ဆင်းမ်ကဒ် ပင်နံပါတ် ထည့်သွင်းပါ၊ သင့်တွင် <xliff:g id="NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
-      <item quantity="one">ဆင်းမ်ကဒ် ပင်နံပါတ် ထည့်သွင်းပါ၊ သင့်စက်ကို ဖွင့်ရန် ဝန်ဆောင်မှုပေးသူသို့ မဆက်သွယ်မီ သင့်တွင် <xliff:g id="NUMBER_0">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
+      <item quantity="other">ဆင်းမ်ကဒ် ပင်နံပါတ် ထည့်သွင်းပါ၊  သင့်တွင် <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။</item>
+      <item quantity="one">ဆင်းမ်ကဒ် ပင်နံပါတ် ထည့်သွင်းပါ၊ သင့်စက်ကို လော့ခ်ဖွင့်ပေးရန်အတွက် ဝန်ဆောင်မှုပေးသူသို့ မဆက်သွယ်မီ <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။</item>
     </plurals>
     <plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
-      <item quantity="other">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ်ကို အပြီးသုံးမရအောင်မပြုမီ သင့်တွင် <xliff:g id="_NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့်ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
-      <item quantity="one">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ်ကို အပြီးသုံးမရအောင်မပြုမီ သင့်တွင် <xliff:g id="_NUMBER_0">%d</xliff:g> ခါ ကြိုးစားခွင့်ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
+      <item quantity="other">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ် အပြီးပိတ်မသွားမီ သင့်တွင် <xliff:g id="_NUMBER_1">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
+      <item quantity="one">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ် အပြီးပိတ်မသွားမီ သင့်တွင် <xliff:g id="_NUMBER_0">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
     </plurals>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 85e0a95..6aa66dd 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -50,7 +50,7 @@
     <string name="keyguard_accessibility_pin_area" msgid="703175752097279029">"Gebied voor pincode"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"Gebied voor pincode van simkaart"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"Gebied voor pukcode van simkaart"</string>
-    <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Volgende alarm ingesteld voor <xliff:g id="ALARM">%1$s</xliff:g>"</string>
+    <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Volgende wekker ingesteld voor <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Delete"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Simkaart uitschakelen"</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
diff --git a/packages/SystemUI/res/drawable/ic_face_unlock.xml b/packages/SystemUI/res/drawable/ic_face_unlock.xml
new file mode 100644
index 0000000..29c2275
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_face_unlock.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ 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
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportHeight="24.0"
+        android:viewportWidth="24.0">
+    <path android:fillColor="?attr/wallpaperTextColor"
+          android:strokeColor="?attr/wallpaperTextColor"
+          android:strokeWidth="1"
+          android:pathData="M9,11.75C8.31,11.75 7.75,12.31 7.75,13C7.75,13.69 8.31,14.25 9,14.25C9.69,14.25 10.25,13.69 10.25,13C10.25,12.31 9.69,11.75 9,11.75ZM15,11.75C14.31,11.75 13.75,12.31 13.75,13C13.75,13.69 14.31,14.25 15,14.25C15.69,14.25 16.25,13.69 16.25,13C16.25,12.31 15.69,11.75 15,11.75ZM12,2C6.48,2 2,6.48 2,12C2,17.52 6.48,22 12,22C17.52,22 22,17.52 22,12C22,6.48 17.52,2 12,2ZM12,20C7.59,20 4,16.41 4,12C4,11.71 4.02,11.42 4.05,11.14C6.41,10.09 8.28,8.16 9.26,5.77C11.07,8.33 14.05,10 17.42,10C18.2,10 18.95,9.91 19.67,9.74C19.88,10.45 20,11.21 20,12C20,16.41 16.41,20 12,20Z"
+    />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_info.xml b/packages/SystemUI/res/drawable/ic_info.xml
new file mode 100644
index 0000000..1eb4004
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_info.xml
@@ -0,0 +1,25 @@
+<!--
+  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
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M22,34h4L26,22h-4v12zM24,4C12.95,4 4,12.95 4,24s8.95,20 20,20 20,-8.95 20,-20S35.05,4 24,4zM24,40c-8.82,0 -16,-7.18 -16,-16S15.18,8 24,8s16,7.18 16,16 -7.18,16 -16,16zM22,18h4v-4h-4v4z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
new file mode 100644
index 0000000..255e377
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
@@ -0,0 +1,117 @@
+<?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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector android:height="24dp"
+                android:width="24dp"
+                android:viewportHeight="102"
+                android:viewportWidth="102"
+                android:tint="?attr/singleToneColor">
+            <group android:name="_R_G">
+                <group android:name="_R_G_L_0_G" android:translateX="53.086" android:translateY="48.907000000000004" android:pivotX="-2.083" android:pivotY="2.083" android:rotation="90">
+                    <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0" android:rotation="100.1" android:scaleX="0.7979999999999999" android:scaleY="0.7979999999999999">
+                        <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M17.15 -37.84 C30.19,-31.91 39.52,-19.62 41.9,-4.86 C42.15,-3.39 43.45,-2.31 44.95,-2.31 C46.88,-2.31 48.34,-4.06 48.05,-5.94 C44.37,-27.64 27.64,-45.91 0.84,-48.09 C-1.08,-48.25 -2.17,-45.91 -0.83,-44.53 C-0.83,-44.53 9.87,-33.83 9.87,-33.83 C10.67,-33.04 11.92,-33.04 12.76,-33.79 C12.76,-33.79 17.15,-37.84 17.15,-37.84c "/>
+                    </group>
+                    <group android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0" android:rotation="87.2" android:scaleX="0.77" android:scaleY="0.77">
+                        <path android:name="_R_G_L_0_G_D_1_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-21.32 42.01 C-34.36,36.07 -43.68,23.78 -46.07,9.02 C-46.33,7.55 -47.62,6.47 -49.12,6.47 C-51.04,6.47 -52.51,8.23 -52.21,10.11 C-48.53,31.81 -31.81,50.08 -5.01,52.25 C-3.09,52.42 -2,50.08 -3.34,48.7 C-3.34,48.7 -14.04,38 -14.04,38 C-14.84,37.21 -16.11,37.19 -16.93,37.96 C-16.93,37.96 -21.32,42.01 -21.32,42.01c "/>
+                    </group>
+                    <path android:name="_R_G_L_0_G_D_2_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M40.77 9.4 C40.77,9.4 -9.4,-40.77 -9.4,-40.77 C-11.91,-43.28 -15.67,-43.28 -18.18,-40.77 C-18.18,-40.77 -44.94,-14.01 -44.94,-14.01 C-47.45,-11.5 -47.45,-7.74 -44.94,-5.23 C-44.94,-5.23 5.23,44.94 5.23,44.94 C7.74,47.45 11.51,47.45 14.01,44.94 C14.01,44.94 40.77,18.18 40.77,18.18 C43.28,15.67 43.28,11.91 40.77,9.4c  M3.85 34.82 C3.85,34.82 -34.4,-3.44 -34.4,-3.44 C-34.4,-3.44 -7.64,-30.19 -7.64,-30.19 C-7.64,-30.19 30.61,8.06 30.61,8.06 C30.61,8.06 3.85,34.82 3.85,34.82c "/>
+                </group>
+            </group>
+            <group android:name="time_group"/>
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="100.1" android:valueTo="0" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+
+    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="scaleX" android:duration="333" android:startOffset="0" android:valueFrom="0.798" android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="333" android:startOffset="0" android:valueFrom="0.798" android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+
+    <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="87.2" android:valueTo="0" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+
+    <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="scaleX" android:duration="333" android:startOffset="0" android:valueFrom="0.77" android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="333" android:startOffset="0" android:valueFrom="0.77" android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+
+    <target android:name="_R_G_L_0_G">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="90" android:valueTo="0" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index 03bba53..dd74cadd 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -16,5 +16,6 @@
 <inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape>
         <solid android:color="@color/qs_background_dark"/>
+        <corners android:radius="?android:attr/dialogCornerRadius" />
     </shape>
 </inset>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 2fd4df4..d0d379c 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -40,6 +40,7 @@
             android:gravity="center_horizontal"
             android:textStyle="italic"
             android:textColor="?attr/wallpaperTextColorSecondary"
+            android:textSize="16sp"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:visibility="gone" />
 
@@ -50,6 +51,7 @@
             android:gravity="center_horizontal"
             android:textStyle="italic"
             android:textColor="?attr/wallpaperTextColorSecondary"
+            android:textSize="16sp"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:accessibilityLiveRegion="polite" />
 
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 2e35d86..6b5bd12 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -23,23 +23,22 @@
         android:clickable="true"
         android:orientation="vertical"
         android:paddingStart="@*android:dimen/notification_content_margin_start"
+        android:paddingEnd="@*android:dimen/notification_content_margin_end"
         android:background="@color/notification_guts_bg_color"
         android:theme="@*android:style/Theme.DeviceDefault.Light">
 
     <!-- Package Info -->
-    <LinearLayout
+    <RelativeLayout
         android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/notification_header_height"
+        android:layout_height="@dimen/notification_guts_header_height"
         android:clipChildren="false"
-        android:paddingTop="@*android:dimen/notification_header_padding_top"
-        android:paddingBottom="@*android:dimen/notification_header_padding_bottom"
-        android:gravity="center_vertical"
-        android:orientation="horizontal" >
+        android:clipToPadding="false"
+        android:layout_marginTop="@*android:dimen/notification_header_padding_top" >
         <ImageView
             android:id="@+id/pkgicon"
-            android:layout_width="@*android:dimen/notification_header_icon_size"
-            android:layout_height="@*android:dimen/notification_header_icon_size"
-            android:layout_marginEnd="3dp"/>
+            android:layout_width="@dimen/notification_guts_header_height"
+            android:layout_height="@dimen/notification_guts_header_height"
+            android:layout_marginEnd="3dp" />
         <TextView
             android:id="@+id/pkgname"
             android:layout_width="wrap_content"
@@ -47,7 +46,9 @@
             android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info"
             android:layout_marginStart="3dp"
             android:layout_marginEnd="2dp"
-            android:singleLine="true"/>
+            android:singleLine="true"
+            android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/pkgicon" />
         <TextView
             android:id="@+id/pkg_group_divider"
             android:layout_width="wrap_content"
@@ -55,7 +56,9 @@
             android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info"
             android:layout_marginStart="2dp"
             android:layout_marginEnd="2dp"
-            android:text="@*android:string/notification_header_divider_symbol"/>
+            android:text="@*android:string/notification_header_divider_symbol"
+            android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/pkgname" />
         <TextView
             android:id="@+id/group_name"
             android:layout_width="wrap_content"
@@ -64,82 +67,103 @@
             android:layout_marginStart="2dp"
             android:layout_marginEnd="2dp"
             android:ellipsize="end"
-            android:maxLines="1"/>
-    </LinearLayout>
+            android:maxLines="1"
+            android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/pkg_group_divider" />
+        <ImageButton
+            android:id="@+id/info"
+            android:src="@drawable/ic_info"
+            android:tint="?android:attr/colorAccent"
+            android:layout_width="@dimen/notification_guts_header_height"
+            android:layout_height="@dimen/notification_guts_header_height"
+            android:contentDescription="@string/notification_more_settings"
+            android:background="@drawable/ripple_drawable"
+            android:layout_alignParentEnd="true" />
+    </RelativeLayout>
 
-    <!-- Channel Info Block -->
     <LinearLayout
+        android:id="@+id/prompt"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="20dp"
-        android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
+        android:layout_marginBottom="@dimen/notification_guts_button_spacing"
+        android:layout_marginTop="@*android:dimen/notification_header_padding_top"
         android:orientation="vertical">
-        <!-- Channel Text -->
+
+        <!-- Channel Info Block -->
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:orientation="horizontal">
+            android:orientation="vertical">
             <!-- Channel Name -->
             <TextView
                 android:id="@+id/channel_name"
-                android:layout_width="0dp"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
                 android:layout_marginBottom="6dp"
                 style="@style/TextAppearance.NotificationInfo.Primary" />
-            <!-- Ban Channel Switch -->
-            <Switch
-                android:id="@+id/channel_enabled_switch"
+            <!-- Question prompt -->
+            <TextView
+                android:id="@+id/block_prompt"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="end|center_vertical"
-                android:contentDescription="@string/notification_channel_switch_accessibility"
-                android:background="@null" />
+                style="@style/TextAppearance.NotificationInfo.Secondary" />
         </LinearLayout>
-        <!-- Secondary Text - only one shows at a time -->
-        <TextView
-            android:id="@+id/channel_disabled"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/notification_channel_disabled"
-            style="@style/TextAppearance.NotificationInfo.Secondary.Warning" />
-        <TextView
-            android:id="@+id/num_channels_desc"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/notification_channel_disabled"
-            style="@style/TextAppearance.NotificationInfo.Secondary" />
-        <!-- Optional link to app. Only appears if the channel is not disabled -->
-        <TextView
-            android:id="@+id/app_settings"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-            android:ellipsize="end"
-            android:maxLines="1"
-            style="@style/TextAppearance.NotificationInfo.Secondary.Link"/>
-    </LinearLayout>
 
-    <!-- Settings and Done buttons -->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="48dp"
-        android:orientation="horizontal"
-        android:gravity="end"
-        android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
-        android:layout_marginBottom="8dp" >
-        <TextView
-            android:id="@+id/more_settings"
-            android:text="@string/notification_more_settings"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_marginEnd="8dp"
-            style="@style/TextAppearance.NotificationInfo.Button"/>
-        <TextView
-            android:id="@+id/done"
-            android:text="@string/notification_done"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            style="@style/TextAppearance.NotificationInfo.Button"/>
+        <!-- Settings and Done buttons -->
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_marginTop="@dimen/notification_guts_button_spacing"
+            android:gravity="end" >
+
+            <!-- Optional link to app. Only appears if the channel is not disabled and the app
+            asked for it -->
+            <TextView
+                android:id="@+id/app_settings"
+                android:text="@string/notification_app_settings"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:ellipsize="end"
+                android:maxLines="1"
+                style="@style/TextAppearance.NotificationInfo.Button"/>
+            <TextView
+                android:id="@+id/block"
+                android:text="@string/inline_stop_button"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                style="@style/TextAppearance.NotificationInfo.Button"/>
+            <TextView
+                android:id="@+id/keep"
+                android:text="@string/inline_keep_button"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginEnd="-8dp"
+                style="@style/TextAppearance.NotificationInfo.Button"/>
+        </LinearLayout>
     </LinearLayout>
+    <RelativeLayout
+        android:id="@+id/confirmation"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/notification_guts_button_spacing"
+        android:layout_marginTop="@*android:dimen/notification_header_padding_top"
+        android:visibility="gone"
+        android:orientation="horizontal" >
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/notification_channel_disabled"
+            style="@style/TextAppearance.NotificationInfo.Secondary.Warning"/>
+        <TextView
+            android:id="@+id/undo"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/inline_undo"
+            android:layout_alignParentEnd="true"
+            android:layout_marginEnd="-8dp"
+            style="@style/TextAppearance.NotificationInfo.Button"/>
+    </RelativeLayout>
 </com.android.systemui.statusbar.NotificationInfo>
diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/res/layout/rotate_suggestion.xml
new file mode 100644
index 0000000..7762950
--- /dev/null
+++ b/packages/SystemUI/res/layout/rotate_suggestion.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    >
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/rotate_suggestion"
+        android:layout_width="@dimen/navigation_extra_key_width"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="2dp"
+        android:visibility="invisible"
+        android:scaleType="centerInside"
+    />
+    <!-- TODO android:contentDescription -->
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index bef0830..c5e5ee1 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -43,6 +43,8 @@
             android:layout_width="@dimen/qs_panel_width"
             android:layout_height="match_parent"
             android:layout_gravity="@integer/notification_panel_layout_gravity"
+            android:layout_marginStart="@dimen/notification_side_paddings"
+            android:layout_marginEnd="@dimen/notification_side_paddings"
             android:clipToPadding="false"
             android:clipChildren="false"
             systemui:viewType="com.android.systemui.plugins.qs.QS" />
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 15a7d4c..fb756e3 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tik om te demp."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s volumekontroles word gewys. Swiep na bo om toe te maak."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Volumekontroles is versteek"</string>
+    <string name="output_title" msgid="5355078100792942802">"Media-uitvoer"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Foonoproep-uitvoer"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Geen toestelle gekry nie"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Geen toestelle gekry nie. Probeer om <xliff:g id="SERVICE">%1$s</xliff:g> aan te skakel"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth en Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Stelsel-UI-ontvanger"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Wys persentasie van ingebedde battery"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Wys batteryvlakpersentasie binne die statusbalkikoon wanneer dit nie laai nie"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Vou uit"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimeer"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Maak toe"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Sleep af om toe te maak"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Kieslys"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in beeld-in-beeld"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index ee9acae..077131c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ።"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"የ%s ድምጽ መቆጣጠሪያዎች ይታያሉ። ለማሰናበት ወደ ላይ ያንሸራትቱ።"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"የድምጽ መቆጣጠሪያዎች ተደብቀዋል"</string>
+    <string name="output_title" msgid="5355078100792942802">"የሚዲያ ውጽዓት"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"የስልክ ጥሪ ውፅዓት"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"ምንም መሣሪያዎች አልተገኙም"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"ምንም መሣሪያዎች አልተገኙም። <xliff:g id="SERVICE">%1$s</xliff:g>ን ማብራት ይሞክሩ።"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ብሉቱዝ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ብሉቱዝ እና Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"የስርዓት በይነገጽ መቃኛ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"የተቀላቀለ የባትሪ አጠቃቀም መቶኛ አሳይ"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ኃይል በማይሞላበት ጊዜ በሁነታ አሞሌ አዶ ውስጥ የባትሪ ደረጃ መቶኛን አሳይ"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"ዘርጋ"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"አሳንስ"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"ዝጋ"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ለማሰናበት ወደ ታች ይጎትቱ"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"ምናሌ"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> በስዕል-ላይ-ስዕል ውስጥ ነው"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1d8cb4e..e5db8de 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -26,7 +26,7 @@
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"تظهر شاشاتك المعروضة مؤخرًا هنا"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"إزالة التطبيقات الحديثة"</string>
     <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
-      <item quantity="zero">‏ لا توجد أية شاشات (%d) في النظرة العامة</item>
+      <item quantity="zero">‏ لا توجد أي شاشات (%d) في النظرة العامة</item>
       <item quantity="two">‏شاشتان (%d) في النظرة العامة</item>
       <item quantity="few">‏%d شاشات في النظرة العامة</item>
       <item quantity="many">‏%d شاشة في النظرة العامة</item>
@@ -302,7 +302,7 @@
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"لا تتوفر شبكة"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏إيقاف Wi-Fi"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"‏تم تشغيل Wi-Fi"</string>
-    <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"‏لا تتوفر أية شبكة Wi-Fi"</string>
+    <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"‏لا تتوفر أي شبكة Wi-Fi"</string>
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"إرسال"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"جارٍ الإرسال"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"جهاز لا يحمل اسمًا"</string>
@@ -511,6 +511,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"‏%1$s. انقر لكتم الصوت."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"‏تم عرض %s عنصر تحكم في مستوى الصوت. يمكنك التمرير سريعًا لأعلى للتجاهل."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"تم إخفاء عناصر التحكم في مستوى الصوت"</string>
+    <string name="output_title" msgid="5355078100792942802">"إخراج الوسائط"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"إخراج المكالمة الهاتفية"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"لم يتم العثور على أي أجهزة."</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"لم يتم العثور على أي أجهزة. جرِّب تفعيل <xliff:g id="SERVICE">%1$s</xliff:g>."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"البلوتوث"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"‏البلوتوث وWi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"أداة ضبط واجهة مستخدم النظام"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"عرض نسبة البطارية المدمجة"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"عرض نسبة مستوى البطارية داخل رمز شريط الحالة أثناء عدم الشحن"</string>
@@ -748,6 +755,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"توسيع"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"تصغير"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"إغلاق"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"اسحب لأسفل للإلغاء"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"القائمة"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> يظهر في صورة داخل صورة"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 098b1cd..1b2972b 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -492,6 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Çoxsaylı ton olan ikili tezlik"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Münasiblik"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Zənglər"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Zəng"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrasiya"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Susdurun"</string>
@@ -502,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Səssiz etmək üçün klikləyin."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s həcm nəzarəti göstərilir. Bitirmək üçün yuxarı çəkin."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Həcm nəzarət gizlədilib"</string>
+    <string name="output_title" msgid="5355078100792942802">"Media çıxışı"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Zəng girişi"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Heç bir cihaz tapılmadı"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Cihaz tapılmadı. <xliff:g id="SERVICE">%1$s</xliff:g> xidmətini aktiv edin"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth və Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Daxil batareya faizini göstərin"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Elektrik şəbəsinə qoşulu olmayan zaman batareya səviyyəsini status paneli ikonası daxilində göstərin"</string>
@@ -723,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Genişləndirin"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Kiçildin"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Bağlayın"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Rədd etmək üçün aşağı çəkin"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menyu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> şəkil içində şəkildədir"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index fd42eb5..2d3635c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Dodirnite da biste isključili zvuk."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Kontrole za jačinu zvuka (%s) su prikazane. Prevucite nagore da biste ih odbacili."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrole za jačinu zvuka su sakrivene"</string>
+    <string name="output_title" msgid="5355078100792942802">"Izlaz medija"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Izlaz za telefonski poziv"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nije pronađen nijedan uređaj"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nije pronađen nijedan uređaj. Probajte da uključite uslugu <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth i Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Tjuner za korisnički interfejs sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Prikazuj ugrađeni procenat baterije"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikazivanje nivoa napunjenosti baterije u procentima unutar ikone na statusnoj traci kada se baterija ne puni"</string>
@@ -730,6 +737,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Prevucite nadole da biste odbili"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meni"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je slika u slici"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index e82dbff..27e3a7d 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -509,6 +509,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Дакраніцеся, каб адключыць гук"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Паказваецца наступная колькасць рэгулятараў гучнасці: %s. Правядзіце пальцам уверх, каб закрыць іх."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Рэгулятары гучнасці схаваны"</string>
+    <string name="output_title" msgid="5355078100792942802">"Вывад мультымедыя"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Прылада вываду тэлефонных выклікаў"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Прылады не знойдзены"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Прылады не знойдзены. Паспрабуйце ўключыць <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth і Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Наладка сістэмнага інтэрфейсу карыстальніка"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Паказваць працэнт зараду акумулятара"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Паказваць працэнт узроўню акумулятара ўнутры значка панэлі стану, калі ён не зараджаецца"</string>
@@ -738,6 +745,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Разгарнуць"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Згарнуць"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Закрыць"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Перацягніце ўніз, каб адхіліць"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Меню"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> з’яўляецца відарысам у відарысе"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ccdc44b..6a93d9e 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Докоснете, за да заглушите звука."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Показани са контролите за силата на звука на %s. Прекарайте пръст нагоре, за да ги скриете."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Контролите за силата на звука са скрити"</string>
+    <string name="output_title" msgid="5355078100792942802">"Изходяща мултимедия"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Изходящи телефонни обаждания"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Няма намерени устройства"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Няма намерени устройства. Включете <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth и Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Тунер на системния потребителски интерфейс"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Показване на процента на вградената батерия"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Показване на процента на нивото на батерията в иконата на лентата на състоянието, когато не се зарежда"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Разгъване"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Намаляване"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Затваряне"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Преместете надолу с плъзгане, за да отхвърлите"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Меню"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> е в режима „Картина в картината“"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 96028f7..4b163ec 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ব্লুটুথ"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"ডুয়েল মাল্টি টোন ফ্রিকোয়েন্সি"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"অ্যাক্সেসযোগ্যতা"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"কল"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"রিং"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ভাইব্রেট"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"মিউট"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s। নিঃশব্দ করতে ট্যাপ করুন।"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s ভলিউম নিয়ন্ত্রণগুলি দেখানো হয়েছে৷ খারিজ করতে উপরের দিকে সোয়াইপ করুন৷"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"ভলিউম নিয়ন্ত্রণগুলি লুকানো রয়েছে"</string>
+    <string name="output_title" msgid="5355078100792942802">"মিডিয়া আউটপুট"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ফোন কল আউটপুট"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"কোনও ডিভাইস খুঁজে পাওয়া যায়নি"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"কোনও ডিভাইস খুঁজে পাওয়া যায়নি। <xliff:g id="SERVICE">%1$s</xliff:g> চালু করার চেষ্টা করুন"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ব্লুটুথ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"ওয়াই-ফাই"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ব্লুটুথ এবং ওয়াই-ফাই"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"সিস্টেম UI টিউনার"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"এম্বেড করা ব্যাটারির শতকরা হার দেখায়"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"যখন চার্জ করা হবে না তখন স্থিতি দন্ডের আইকনের ভিতরে ব্যাটারি স্তরের শতকার হার দেখায়"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"বড় করুন"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ছোটো করুন"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"বন্ধ করুন"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"খারিজ করতে নিচের দিকে টেনে আনুন"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"মেনু"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"ছবির-মধ্যে-ছবি তে <xliff:g id="NAME">%s</xliff:g> আছেন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index f09bb1f..fc246c4 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -153,9 +153,9 @@
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Nema SIM kartice."</string>
-    <string name="accessibility_cell_data" msgid="5326139158682385073">"Mobilni podaci"</string>
-    <string name="accessibility_cell_data_on" msgid="5927098403452994422">"Mobilni podaci su uključeni"</string>
-    <string name="accessibility_cell_data_off" msgid="443267573897409704">"Mobilni podaci su isključeni"</string>
+    <string name="accessibility_cell_data" msgid="5326139158682385073">"Prijenos podataka na mobilnoj mreži"</string>
+    <string name="accessibility_cell_data_on" msgid="5927098403452994422">"Prijenos podataka na mobilnoj mreži je uključen"</string>
+    <string name="accessibility_cell_data_off" msgid="443267573897409704">"Prijenos podataka na mobilnoj mreži je isključen"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Dijeljenje Bluetooth veze."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Način rada u avionu."</string>
     <string name="accessibility_vpn_on" msgid="5993385083262856059">"VPN uključen."</string>
@@ -240,9 +240,9 @@
     <string name="accessibility_ambient_display_charging" msgid="9084521679384069087">"Punjenje"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G prijenos podataka je pauzirano"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G prijenos podataka je pauzirano"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="6801382439018099779">"Mobilni podaci su pauzirani"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="6801382439018099779">"Prijenos podataka je pauziran"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prijenos podataka je pauziran"</string>
-    <string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Dostigli ste ograničenje za prijenos podataka koje ste postavili. Više ne koristite mobilne podatke.\n\nUkoliko nastavite koristiti mobilne podatke, mogući su troškovi za prijenos podataka."</string>
+    <string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Dostigli ste ograničenje za prijenos podataka koje ste postavili. Više ne koristite prijenos podataka na mobilnoj mreži.\n\nUkoliko nastavite koristiti prijenos podataka na mobilnoj mreži, mogući su troškovi za prijenos podataka."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Traženje GPS signala"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija utvrđena GPS signalom"</string>
@@ -315,7 +315,7 @@
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Pristupna tačka"</string>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obavještenja"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Svjetiljka"</string>
-    <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobilni podaci"</string>
+    <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Prijenos podataka na mobilnoj mreži"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Prijenos podataka"</string>
     <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Preostala količina podataka"</string>
     <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Prekoračeno"</string>
@@ -412,16 +412,16 @@
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil može biti nadziran"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Mreža može biti nadzirana"</string>
     <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža može biti nadzirana"</string>
-    <string name="quick_settings_disclosure_management_monitoring" msgid="6645176135063957394">"Vaša organizacija upravlja ovim uređajem i može pratiti mrežni promet."</string>
-    <string name="quick_settings_disclosure_named_management_monitoring" msgid="370622174777570853">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> upravlja ovim uređajem i može pratiti vaš mrežni promet"</string>
+    <string name="quick_settings_disclosure_management_monitoring" msgid="6645176135063957394">"Vaša organizacija upravlja ovim uređajem i može pratiti mrežni saobraćaj."</string>
+    <string name="quick_settings_disclosure_named_management_monitoring" msgid="370622174777570853">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> upravlja ovim uređajem i može pratiti vaš mrežni saobraćaj"</string>
     <string name="quick_settings_disclosure_management_named_vpn" msgid="1085137869053332307">"Uređajem upravlja vaša organizacija i povezan je s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
     <string name="quick_settings_disclosure_named_management_named_vpn" msgid="6290456493852584017">"Uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> i povezan je s aplikacijom <xliff:g id="VPN_APP">%2$s</xliff:g>"</string>
     <string name="quick_settings_disclosure_management" msgid="3294967280853150271">"Uređajem upravlja vaša organizacija"</string>
     <string name="quick_settings_disclosure_named_management" msgid="1059403025094542908">"Ovim uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>."</string>
     <string name="quick_settings_disclosure_management_vpns" msgid="3698767349925266482">"Uređajem upravlja vaša organizacija i povezan je s VPN-ovima"</string>
     <string name="quick_settings_disclosure_named_management_vpns" msgid="7777821385318891527">"Uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> i povezan je s VPN-ovima"</string>
-    <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="5125463987558278215">"Vaša organizacija može pratiti mrežni promet na vašem profilu."</string>
-    <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8973606847896650284">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> može pratiti mrežni promet na vašem radnom profilu"</string>
+    <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="5125463987558278215">"Vaša organizacija može pratiti mrežni saobraćaj na vašem profilu."</string>
+    <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8973606847896650284">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> može pratiti mrežni saobraćaj na vašem radnom profilu"</string>
     <string name="quick_settings_disclosure_monitoring" msgid="679658227269205728">"Mreža može biti nadzirana"</string>
     <string name="quick_settings_disclosure_vpns" msgid="8170318392053156330">"Uređaj je povezan s VPN-ovima"</string>
     <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="3494535754792751741">"Radni profil je povezan s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -438,10 +438,10 @@
     <string name="monitoring_button_view_policies" msgid="100913612638514424">"Prikaži pravila"</string>
     <string name="monitoring_description_named_management" msgid="5281789135578986303">"Vašim uređajem upravlja organizacija <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVaš administrator može nadgledati i upravljati vašim postavkama, korporativnom pristupu, aplikacijama, podacima koji su povezani s vašim uređajem i informacijama o lokaciji vašeg uređaja.\n\nZa više informacija, obratite se svom administratoru."</string>
     <string name="monitoring_description_management" msgid="4573721970278370790">"Vašim uređajem upravlja vaša organizacija.\n\nVaš administrator može nadgledati i upravljati vašim postavkama, korporativnom pristupu, aplikacijama, podacima koji su povezani s vašim uređajem i informacijama o lokaciji vašeg uređaja.\n\nZa više informacija, obratite se svom administratoru."</string>
-    <string name="monitoring_description_management_ca_certificate" msgid="5202023784131001751">"Vaša organizacija je instalirala CA certifikat na ovom uređaju. Vaš promet preko sigurne mreže može se pratiti."</string>
-    <string name="monitoring_description_managed_profile_ca_certificate" msgid="4683248196789897964">"Vaša organizacija je instalirala CA certifikat na vašem radnom profilu. Vaš promet preko sigurne mreže može se pratiti."</string>
-    <string name="monitoring_description_ca_certificate" msgid="7886985418413598352">"CA certifikat je instaliran na ovom uređaju. Vaš promet preko sigurne mreže može se pratiti."</string>
-    <string name="monitoring_description_management_network_logging" msgid="7184005419733060736">"Vaš administrator je uključio zapisivanje na mreži, čime se prati promet na vašem uređaju."</string>
+    <string name="monitoring_description_management_ca_certificate" msgid="5202023784131001751">"Vaša organizacija je instalirala CA certifikat na ovom uređaju. Vaš saobraćaj preko sigurne mreže može se pratiti."</string>
+    <string name="monitoring_description_managed_profile_ca_certificate" msgid="4683248196789897964">"Vaša organizacija je instalirala CA certifikat na vašem radnom profilu. Vaš saobraćaj preko sigurne mreže može se pratiti."</string>
+    <string name="monitoring_description_ca_certificate" msgid="7886985418413598352">"CA certifikat je instaliran na ovom uređaju. Vaš saobraćaj preko sigurne mreže može se pratiti."</string>
+    <string name="monitoring_description_management_network_logging" msgid="7184005419733060736">"Vaš administrator je uključio zapisivanje na mreži, čime se prati saobraćaj na vašem uređaju."</string>
     <string name="monitoring_description_named_vpn" msgid="7403457334088909254">"Povezani ste s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g> koja može pratiti vašu aktivnost na mreži, uključujući e-poštu i web lokacije."</string>
     <string name="monitoring_description_two_named_vpns" msgid="4198511413729213802">"Povezani ste s aplikacijama <xliff:g id="VPN_APP_0">%1$s</xliff:g> i <xliff:g id="VPN_APP_1">%2$s</xliff:g> koje mogu pratiti vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web lokacije."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="1427905889862420559">"Vaš radni profil je povezan s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poruke i web lokacije."</string>
@@ -462,7 +462,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="1828472472674709532">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poruke, aplikacije i web lokacije."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
-    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste na aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vaše privatne aktivnosti na mreži, uključujući e-poštu, aplikacije i web stranice."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste na aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vaše privatne aktivnosti na mreži, uključujući e-poštu, aplikacije i web lokacije."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Vašim radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poruke, aplikacije i web lokacije.\n\nZa više informacija, obratite se svom administratoru."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poruke, aplikacije i web lokacije.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži."</string>
     <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Otključano za korisnika <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
@@ -494,6 +494,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Dvostruka višemelodijska frekvencija"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Pristupačnost"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Pozivi"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Zvono"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibriranje"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Isključi zvuk"</string>
@@ -506,6 +507,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Dodirnite da isključite zvuk."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Prikazane kontrole jačine zvuka za: %s. Prevucite prema gore za odbacivanje."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrole jačine zvuka sakrivene"</string>
+    <string name="output_title" msgid="5355078100792942802">"Izlaz za medijske fajlove"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Izlaz za telefonske pozive"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nije pronađen nijedan uređaj"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nije pronađen nijedan uređaj. Pokušajte uključiti <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth i Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Podešavač za korisnički interfejs sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Prikaži ugrađeni postotak baterije"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikazuje postotak nivoa baterije unutar ikone na statusnoj traci kada se baterija ne puni"</string>
@@ -731,6 +739,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Povucite prema dolje da odbacite"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meni"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je u načinu priakza Slika u slici"</string>
@@ -768,7 +778,7 @@
     <string name="instant_apps_message" msgid="8116608994995104836">"Za instant aplikacije nije potrebna instalacija"</string>
     <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
     <string name="go_to_web" msgid="2650669128861626071">"Idi na preglednik"</string>
-    <string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>
+    <string name="mobile_data" msgid="7094582042819250762">"Prijenos podataka na mobilnoj mreži"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi veza je isključena"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"Bluetooth je isključen"</string>
     <string name="dnd_is_off" msgid="6167780215212497572">"Opcija Ne ometaj je isključena"</string>
@@ -780,6 +790,6 @@
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Zamijeni"</string>
     <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikacije koje rade u pozadini"</string>
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"Dodirnite za detalje o potrošnji baterije i prijenosa podataka"</string>
-    <string name="data_usage_disable_mobile" msgid="5116269981510015864">"Želite li isključiti prijenos mobilnih podataka?"</string>
+    <string name="data_usage_disable_mobile" msgid="5116269981510015864">"Želite li isključiti prijenos podataka na mobilnoj mreži?"</string>
     <string name="touch_filtered_warning" msgid="8671693809204767551">"Postavke ne mogu potvrditi vaš odgovor jer aplikacija zaklanja zahtjev za odobrenje."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index dacf9d7..4ff8e2c 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -35,8 +35,8 @@
     <string name="battery_low_title" msgid="6456385927409742437">"Queda poca bateria"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>."</string>
     <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>. La funció Estalvi de bateria està activada."</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Càrrega d\'USB no admesa.\nUtilitza només el carregador proporcionat."</string>
-    <string name="invalid_charger_title" msgid="3515740382572798460">"La càrrega per USB no és compatible."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"Pujada d\'USB no admesa.\nUtilitza només el carregador proporcionat."</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"La pujada per USB no és compatible."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Fes servir només el carregador proporcionat amb el dispositiu."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Configuració"</string>
     <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Vols activar la funció Estalvi de bateria?"</string>
@@ -342,7 +342,7 @@
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Divideix la pantalla cap a la dreta"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"S\'està carregant"</string>
-    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la càrrega"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la pujada"</string>
     <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No s\'està carregant"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Cerca"</string>
@@ -369,9 +369,9 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silenci\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Només\ninterr. prior."</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Només\nalarmes"</string>
-    <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
-    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Càrrega ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
-    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Càrrega lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
+    <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la pujada)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Pujada ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Pujada lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Canvia d\'usuari"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Canvia d\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Toca per silenciar."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Es mostren %s controls de volum. Llisca cap amunt per ignorar-ho."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Els controls de volum estan amagats"</string>
+    <string name="output_title" msgid="5355078100792942802">"Sortida de contingut multimèdia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Sortida de trucades"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"No s\'ha trobat cap dispositiu"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"No s\'ha trobat cap dispositiu. Prova d\'activar <xliff:g id="SERVICE">%1$s</xliff:g>."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth i Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Personalitzador d\'interfície d\'usuari"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostra el percentatge de la bateria inserit"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostra el percentatge del nivell de bateria dins de la icona de la barra d\'estat quan no s\'estigui carregant"</string>
@@ -584,7 +591,7 @@
       <item quantity="one">%d minut</item>
     </plurals>
     <string name="battery_panel_title" msgid="7944156115535366613">"Consum de la bateria"</string>
-    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"La funció Estalvi de bateria no està disponible durant la càrrega"</string>
+    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"La funció Estalvi de bateria no està disponible durant la pujada"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Estalvi de bateria"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Redueix el rendiment i les dades en segon pla"</string>
     <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botó <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Desplega"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimitza"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Tanca"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrossega cap avall per ignorar-ho"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menú"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> està en pantalla en pantalla"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4166697..9c7de6a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -509,6 +509,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Klepnutím vypnete zvuk."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Ovládací prvky hlasitosti aplikace %s jsou zobrazeny. Zavřete je přejetím prstem."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Ovládací prvky hlasitosti jsou skryty"</string>
+    <string name="output_title" msgid="5355078100792942802">"Výstup médií"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Výstup telefonního hovoru"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nebyla nalezena žádná zařízení"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nebyla nalezena žádná zařízení. Zkuste zapnout <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth a Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Nástroj na ladění uživatelského rozhraní systému"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Zobrazovat vložené procento nabití baterie"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Když neprobíhá nabíjení, zobrazit v ikoně na stavovém řádku procento nabití baterie"</string>
@@ -738,6 +745,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbalit"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovat"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Zavřít"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Nápovědu zavřete přetažením dolů"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Nabídka"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"Aplikace <xliff:g id="NAME">%s</xliff:g> je v režimu obraz v obraze"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 52446f8..5438434 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tryk for at slå lyden fra."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Lydstyrkeknapperne for %s er synlige. Stryg op for at lukke."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Lydstyrkeknapperne er skjult"</string>
+    <string name="output_title" msgid="5355078100792942802">"Medieafspilning"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Udgang til telefonopkald"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Der blev ikke fundet nogen enheder"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Der blev ikke fundet nogen enheder. Prøv at aktivere <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth og Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Vis procent for det indbyggede batteri"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Vis procenttallet for batteriniveauet i ikonet for statusbjælken, når der ikke oplades"</string>
@@ -724,6 +731,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Udvid"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimer"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Luk"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"Indstillinger"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Træk nedad for at afvise"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> vises som integreret billede"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 83a8e33..a68ad2a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -507,6 +507,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Zum Stummschalten tippen."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Lautstärkeregler von %s werden angezeigt. Zum Schließen nach oben wischen."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Lautstärkeregler ausgeblendet"</string>
+    <string name="output_title" msgid="5355078100792942802">"Medienausgabe"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Telefonanrufausgabe"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Keine Geräte gefunden"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Keine Geräte gefunden. Aktiviere <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"WLAN"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth und WLAN"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Eingebettete Akku-Prozentzahl anzeigen"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prozentzahl für Akkustand in Statusleistensymbol anzeigen, wenn das Gerät nicht geladen wird"</string>
@@ -728,6 +735,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Maximieren"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimieren"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Schließen"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Zum Schließen nach unten ziehen"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menü"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ist in Bild im Bild"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 9a61828..7464d31 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Πατήστε για σίγαση."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Εμφανίζονται τα στοιχεία ελέγχου έντασης %s. Σύρετε για παράβλεψη."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Έγινε απόκρυψη των στοιχείων ελέγχου έντασης"</string>
+    <string name="output_title" msgid="5355078100792942802">"Έξοδος μέσων"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Έξοδος τηλεφωνικής κλήσης"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Δεν βρέθηκαν συσκευές"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Δεν βρέθηκαν συσκευές. Δοκιμάστε να ενεργοποιήσετε την υπηρεσία <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth και Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Εμφάνιση ποσοστού ενσωματωμένης μπαταρίας"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Εμφάνιση ποσοστού επιπέδου μπαταρίας μέσα στο εικονίδιο της γραμμής κατάστασης όταν δεν γίνεται φόρτιση"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Ανάπτυξη"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Ελαχιστοποίηση"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Κλείσιμο"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Σύρετε προς τα κάτω για παράβλεψη"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Μενού"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"Η λειτουργία picture-in-picture είναι ενεργή σε <xliff:g id="NAME">%s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 87a0ee5..b1b1626 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -492,6 +492,10 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Dual multi-tone frequency"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accessibility"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Calls"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ring"</string>
+    <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrate"</string>
+    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Mute"</string>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -499,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap to mute."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s volume controls shown. Swipe up to dismiss."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Volume controls hidden"</string>
+    <string name="output_title" msgid="5355078100792942802">"Media output"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Phone call output"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"No devices found"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"No devices found. Try turning on <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth and Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Show embedded battery percentage"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Show battery level percentage inside the status bar icon when not charging"</string>
@@ -720,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Close"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Drag down to dismiss"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
@@ -756,7 +769,7 @@
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
     <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
-    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>
+    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"Bluetooth is off"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 6756f86..420dd9d 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -492,6 +492,10 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Dual multi-tone frequency"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accessibility"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Calls"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ring"</string>
+    <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrate"</string>
+    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Mute"</string>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -499,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap to mute."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s volume controls shown. Swipe up to dismiss."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Volume controls hidden"</string>
+    <string name="output_title" msgid="5355078100792942802">"Media output"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Phone call output"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"No devices found"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"No devices found. Try turning on <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth and Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Show embedded battery percentage"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Show battery level percentage inside the status bar icon when not charging"</string>
@@ -720,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Close"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Drag down to dismiss"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
@@ -756,7 +769,7 @@
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
     <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
-    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>
+    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"Bluetooth is off"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 87a0ee5..b1b1626 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -492,6 +492,10 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Dual multi-tone frequency"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accessibility"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Calls"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ring"</string>
+    <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrate"</string>
+    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Mute"</string>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -499,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap to mute."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s volume controls shown. Swipe up to dismiss."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Volume controls hidden"</string>
+    <string name="output_title" msgid="5355078100792942802">"Media output"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Phone call output"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"No devices found"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"No devices found. Try turning on <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth and Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Show embedded battery percentage"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Show battery level percentage inside the status bar icon when not charging"</string>
@@ -720,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Close"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Drag down to dismiss"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
@@ -756,7 +769,7 @@
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
     <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
-    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>
+    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"Bluetooth is off"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 87a0ee5..b1b1626 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -492,6 +492,10 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Dual multi-tone frequency"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accessibility"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Calls"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ring"</string>
+    <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrate"</string>
+    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Mute"</string>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -499,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap to mute."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s volume controls shown. Swipe up to dismiss."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Volume controls hidden"</string>
+    <string name="output_title" msgid="5355078100792942802">"Media output"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Phone call output"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"No devices found"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"No devices found. Try turning on <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth and Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Show embedded battery percentage"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Show battery level percentage inside the status bar icon when not charging"</string>
@@ -720,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Close"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Drag down to dismiss"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
@@ -756,7 +769,7 @@
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
     <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
-    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>
+    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"Bluetooth is off"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 1d70422..4cc96c1 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -492,6 +492,10 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎Bluetooth‎‏‎‎‏‎"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎Dual multi tone frequency‎‏‎‎‏‎"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‏‎‎Accessibility‎‏‎‎‏‎"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‎‎Calls‎‏‎‎‏‎"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‎‎Ring‎‏‎‎‏‎"</string>
+    <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‏‎Vibrate‎‏‎‎‏‎"</string>
+    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‎‏‎Mute‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎%1$s. Tap to unmute.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎%1$s. Tap to set to vibrate. Accessibility services may be muted.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‏‎‏‎‎%1$s. Tap to mute. Accessibility services may be muted.‎‏‎‎‏‎"</string>
@@ -499,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‏‏‎‎%1$s. Tap to mute.‎‏‎‎‏‎"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎%s volume controls shown. Swipe up to dismiss.‎‏‎‎‏‎"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎Volume controls hidden‎‏‎‎‏‎"</string>
+    <string name="output_title" msgid="5355078100792942802">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎Media output‎‏‎‎‏‎"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎Phone call output‎‏‎‎‏‎"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎No devices found‎‏‎‎‏‎"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎No devices found. Try turning on ‎‏‎‎‏‏‎<xliff:g id="SERVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‎Bluetooth‎‏‎‎‏‎"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎Wi-Fi‎‏‎‎‏‎"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‎‎‎Bluetooth and Wi-Fi‎‏‎‎‏‎"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‎System UI Tuner‎‏‎‎‏‎"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎Show embedded battery percentage‎‏‎‎‏‎"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎Show battery level percentage inside the status bar icon when not charging‎‏‎‎‏‎"</string>
@@ -720,6 +731,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎Expand‎‏‎‎‏‎"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎Minimize‎‏‎‎‏‎"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎Close‎‏‎‎‏‎"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‎Settings‎‏‎‎‏‎"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎Drag down to dismiss‎‏‎‎‏‎"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎Menu‎‏‎‎‏‎"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ is in picture-in-picture‎‏‎‎‏‎"</string>
@@ -756,7 +768,7 @@
     <string name="instant_apps" msgid="6647570248119804907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎Instant Apps‎‏‎‎‏‎"</string>
     <string name="instant_apps_message" msgid="8116608994995104836">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎Instant apps don\'t require installation.‎‏‎‎‏‎"</string>
     <string name="app_info" msgid="6856026610594615344">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎App info‎‏‎‎‏‎"</string>
-    <string name="go_to_web" msgid="1106022723459948514">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎Go to web‎‏‎‎‏‎"</string>
+    <string name="go_to_web" msgid="2650669128861626071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‏‏‎Go to browser‎‏‎‎‏‎"</string>
     <string name="mobile_data" msgid="7094582042819250762">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎Mobile data‎‏‎‎‏‎"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‎Wi-Fi is off‎‏‎‎‏‎"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎Bluetooth is off‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index d808119..6901686 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Presiona para silenciar."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Se muestran los controles de volumen de %s. Desliza el dedo para descartar."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Controles de volumen ocultos"</string>
+    <string name="output_title" msgid="5355078100792942802">"Salida multimedia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Salida de llamada telefónica"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"No se encontraron dispositivos"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"No se encontraron dispositivos. Activa <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth y Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizador de IU del sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentaje de la batería integrada"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostrar porcentaje del nivel de batería en el ícono de la barra de estado cuando no se está cargando"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Cerrar"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrastra hacia abajo para descartar"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menú"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> está en modo de imagen en imagen"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 14c2818..a5d5c44 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -494,6 +494,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Multifrecuencia de tono dual"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accesibilidad"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Llamadas"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Hacer sonar"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silenciar"</string>
@@ -504,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Toca para silenciar."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s controles de volumen mostrados. Desliza el dedo hacia arriba para rechazar."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Controles de volumen ocultos"</string>
+    <string name="output_title" msgid="5355078100792942802">"Salida multimedia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Salida de llamadas"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"No se ha podido encontrar ningún dispositivo"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"No se ha podido encontrar ningún dispositivo. Prueba a activar <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi‑Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth y Wi‑Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de IU del sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentaje de batería insertado"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostrar el porcentaje del nivel de batería en el icono de la barra de estado cuando no se esté cargando"</string>
@@ -725,6 +733,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Mostrar"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Cerrar"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"Ajustes"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrastra hacia abajo para ignorar"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menú"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> está en imagen en imagen"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3a5af25..84cbc44 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Puudutage vaigistamiseks."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s helitugevuse juhtnuppu on kuvatud. Loobumiseks pühkige üles."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Helitugevuse juhtnupud on peidetud"</string>
+    <string name="output_title" msgid="5355078100792942802">"Meediaväljund"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Telefonikõne väljund"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Seadmeid ei leitud"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Seadmeid ei leitud. Lülitage sisse teenus <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"WiFi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth ja WiFi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Süsteemi kasutajaliidese tuuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Kuva lisatud akutaseme protsent"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Akutaseme protsendi kuvamine olekuriba ikoonil, kui akut ei laeta"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Laiendamine"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimeeri"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Sule"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Loobumiseks lohistage alla"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menüü"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> on režiimis Pilt pildis"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 87348de..85d3c6e 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -226,8 +226,8 @@
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flasha aktibatuta dago."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flasha desaktibatu egin da."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flasha aktibatu egin da."</string>
-    <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Koloreak alderantzikatzeko aukera desaktibatu egin da."</string>
-    <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Koloreak alderantzikatzeko aukera aktibatu egin da."</string>
+    <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Koloreen alderantzikatzea desaktibatu egin da."</string>
+    <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Koloreen alderantzikatzea aktibatu egin da."</string>
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Konexioa partekatzeko aukera desaktibatu egin da."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Konexioa partekatzeko aukera aktibatu egin da."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Pantaila igortzeari utzi zaio."</string>
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Sakatu hau audioa desaktibatzeko."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Bolumena kontrolatzeko %s aukera daude ikusgai. Pasatu hatza gora baztertzeko."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Ezkutatuta daude bolumena kontrolatzeko aukerak"</string>
+    <string name="output_title" msgid="5355078100792942802">"Multimedia-irteera"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Telefono-deiaren irteera"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Ez da aurkitu gailurik"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Ez da aurkitu gailurik. Aktibatu <xliff:g id="SERVICE">%1$s</xliff:g>."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth konexioa"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi konexioa"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth eta Wi-Fi konexioak"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sistemako erabiltzaile-interfazearen konfiguratzailea"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Erakutsi txertatutako bateriaren ehunekoa"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Erakutsi bateria-mailaren ehunekoa egoera-barraren ikonoan, kargatzen ari ez denean"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Zabaldu"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizatu"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Itxi"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Baztertzeko, arrastatu behera"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menua"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"Pantaila txiki gainjarrian dago <xliff:g id="NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index bb77daa..834397d 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"‏%1$s. برای بی‌صدا کردن ضربه بزنید."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"‏کنترل‌های میزان صدای %s  نشان داده شدند. برای نپذیرفتن انگشتتان را تند بکشید."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"کنترل‌های صدا پنهان هستند"</string>
+    <string name="output_title" msgid="5355078100792942802">"خروجی رسانه"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"خروجی تماس تلفنی"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"دستگاهی پیدا نشد"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"دستگاهی پیدا نشد. <xliff:g id="SERVICE">%1$s</xliff:g> را روشن کنید"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"بلوتوث"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"‏بلوتوث و Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"تنظیم‌کننده واسط کاربری سیستم"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"نمایش درصد شارژ باتری جاسازی شده"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"نمایش درصد سطح باتری در نماد نوار وضعیت، هنگامی که باتری شارژ نمی‌شود"</string>
@@ -724,6 +731,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"بزرگ کردن"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"کوچک کردن"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"بستن"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"تنظیمات"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"برای نپذیرفتن، به پایین بکشید"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"منو"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> درحالت تصویر در تصویر است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 3bebe4b..51a71de 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Mykistä napauttamalla."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Äänenvoimakkuuden säätimiä on näkyvissä (%s). Hylkää pyyhkäisemällä ylös."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Äänenvoimakkuuden säätimet piilotettiin."</string>
+    <string name="output_title" msgid="5355078100792942802">"Median äänentoisto"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Puhelun äänentoisto"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Laitteita ei löytynyt"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Laitteita ei löytynyt. Kokeile ottaa käyttöön <xliff:g id="SERVICE">%1$s</xliff:g>."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth ja Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Näytä akun varaus kuvakkeessa"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Näyttää akun varausprosentin tilapalkin kuvakkeessa, kun laitetta ei ladata."</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Laajenna"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Pienennä"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Sulje"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Hylkää vetämällä alas."</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Valikko"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> on kuva kuvassa ‑tilassa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a2dde85..1ddc394 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Touchez pour couper le son."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Commandes de volume %s affichées. Faire glisser vers le haut pour ignorer."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Les commandes de volume sont masquées"</string>
+    <string name="output_title" msgid="5355078100792942802">"Sortie multimédia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Sortie d\'appel téléphonique"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Aucun appareil trouvé"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Aucun appareil n\'a été trouvé. Essayez d\'activer le <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth et le Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Afficher le pourcentage intégré de charge"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Afficher le pourcentage correspondant au niveau de la pile dans l\'icône de la barre d\'état lorsque l\'appareil n\'est pas en charge."</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Réduire"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Fermer"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Faire glisser vers le bas pour ignorer"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> est en mode d\'incrustation d\'image"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 21952ae..f6e98a3 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -494,6 +494,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"DTMF"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accessibilité"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Appels"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Sonnerie"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibreur"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silencieux"</string>
@@ -504,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Appuyez pour ignorer."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Commandes de volume %s affichées. Faire glisser vers le haut pour ignorer."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Commandes de volume masquées"</string>
+    <string name="output_title" msgid="5355078100792942802">"Sortie multimédia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Sortie de l\'appel téléphonique"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Aucun appareil détecté"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Aucun appareil détecté. Essayez d\'activer le <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth et Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Afficher le pourcentage intégré de la batterie"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Affichez le pourcentage correspondant au niveau de la batterie dans l\'icône de la barre d\'état lorsque l\'appareil n\'est pas en charge."</string>
@@ -725,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Réduire"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Fermer"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Faire glisser vers le bas pour ignorer"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> est en mode Picture-in-picture"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9fbcdec..987ea59 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Toca para silenciar."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Estanse mostrando os controis de volume de %s. Pasa o dedo cara a arriba para ignoralos."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Ocultáronse os controis de volume"</string>
+    <string name="output_title" msgid="5355078100792942802">"Saída multimedia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Saída de chamadas telefónicas"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Non se atopou ningún dispositivo"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Non se atopou ningún dispositivo. Proba a activar <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wifi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth e wifi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Configurador da IU do sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentaxe de batería inserida"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostrar porcentaxe do nivel de batería na icona da barra de estado cando non está en carga"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Despregar"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Pechar"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrastra cara abaixo para ignorar"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menú"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> está na pantalla superposta"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 418f31e..c024531 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"બ્લૂટૂથ"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"દ્વિ બહુ ટોન આવર્તન"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"ઍક્સેસિબિલિટી"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"કૉલ"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"રિંગ કરો"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"વાઇબ્રેટ"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"મ્યૂટ કરો"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s વૉલ્યૂમ નિયંત્રણ બતાવ્યાં. છોડી દેવા માટે સ્વાઇપ કરો."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"વૉલ્યૂમ નિયંત્રણ છુપાવ્યાં"</string>
+    <string name="output_title" msgid="5355078100792942802">"મીડિયાનું આઉટપુટ"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ફોન કૉલનો આઉટપુટ"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"કોઈ ઉપકરણો મળ્યા નથી"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"કોઈ ઉપકરણો મળ્યા નથી. <xliff:g id="SERVICE">%1$s</xliff:g>ને ચાલુ કરવાનો પ્રયાસ કરો"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"બ્લૂટૂથ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"વાઇ-ફાઇ"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"બ્લૂટૂથ અને વાઇ-ફાઇ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"સિસ્ટમ UI ટ્યૂનર"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"એમ્બેડ કરેલ બૅટરી ટકા બતાવો"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"જ્યારે ચાર્જ ન થઈ રહ્યું હોય ત્યારે સ્ટેટસ બાર આયકનની અંદર બૅટરી સ્તર ટકા બતાવો"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"વિસ્તૃત કરો"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"નાનું કરો"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"બંધ કરો"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"છોડી દેવા માટે નીચે ખેંચો"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"મેનૂ"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ચિત્રમાં-ચિત્રની અંદર છે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 1acd6e7..f5f8c7c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ब्लूटूथ"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"दोहरी बहु टोन आवृत्ति"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"सुलभता"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"कॉल"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"आवाज़ चालू है"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"कंपन (वाइब्रेशन)"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"आवाज़ बंद है"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. म्यूट करने के लिए टैप करें."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s वॉल्यूम नियंत्रण दिखाए गए हैं. खारिज करने के लिए स्वाइप करें."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"वॉल्यूम नियंत्रण छिपे हुए हैं"</string>
+    <string name="output_title" msgid="5355078100792942802">"मीडिया आउटपुट"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"फ़ोन कॉल का आउटपुट"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"कोई डिवाइस नहीं मि‍ला"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"कोई डिवाइस नहीं मिला. <xliff:g id="SERVICE">%1$s</xliff:g> को चालू करें"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ब्लूटूथ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"वाई-फ़ाई"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ब्लूटूथ और वाई-फ़ाई"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"सिस्टम यूज़र इंटरफ़ेस (यूआई) ट्यूनर"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"एम्बेड किया गया बैटरी प्रतिशत दिखाएं"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"जब चार्ज नहीं किया जा रहा हो तब स्टेटस बार आइकॉन में बैटरी लेवल का प्रतिशत दिखाएं"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तार करें"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"छोटा करें"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"बंद करें"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"खारिज करने के लिए नीचे खींचें और छोड़ें"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"मेन्यू"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> पिक्चर में पिक्चर के अंदर है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7ba9111..7395b66 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Dodirnite da biste isključili zvuk."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s kontrole glasnoće prikazane. Kliznite prstom prema gore da biste ih odbacili."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrole glasnoće skrivene"</string>
+    <string name="output_title" msgid="5355078100792942802">"Medijski izlaz"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Izlaz telefonskih poziva"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nije pronađen nijedan uređaj"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nije pronađen nijedan uređaj. Pokušajte uključiti uslugu <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth i Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Ugađanje korisničkog sučelja sustava"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Prikaži ugrađeni postotak baterije"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikazivanje postotka razine baterije na ikoni trake statusa kada se ne puni"</string>
@@ -730,6 +737,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Proširivanje"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimiziraj"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Povucite prema dolje da biste odbacili"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Izbornik"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> jest na slici u slici"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 8aa2c71..87ca49a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Koppintson a némításhoz."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"A(z) %s hangvezérlői megjelenítve. Az elvetéshez húzza felfelé az ujját."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Hangvezérlők elrejtve"</string>
+    <string name="output_title" msgid="5355078100792942802">"Médiakimenet"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Telefonhívás-kimenet"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nem találhatók eszközök"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nem találhatók eszközök. Próbálja meg a(z) <xliff:g id="SERVICE">%1$s</xliff:g> bekapcsolásával"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth és Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Kezelőfelület-hangoló"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"A beépített akkumulátor töltöttségi szintjének megjelenítése"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Az akkumulátor töltöttségi szintjének megjelenítése az állapotsori ikonban, amikor az eszköz nem töltődik"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Kibontás"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Kis méret"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Bezárás"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Elvetéshez húzza lefelé"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menü"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"A(z) <xliff:g id="NAME">%s</xliff:g> kép a képben funkciót használ"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 2841074..b6172c8 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s։ Հպեք՝ ձայնը անջատելու համար։"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s ձայնի ուժգնության կառավարները ցուցադրված են: Մատը սահեցրեք վերև՝ փակելու համար:"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Ձայնի ուժգնության կառավարները թաքցված են"</string>
+    <string name="output_title" msgid="5355078100792942802">"Մեդիա արտածում"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Հեռախոսազանգի հնչեցում"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Սարքեր չեն գտնվել"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Սարքեր չեն գտնվել: Միացրեք <xliff:g id="SERVICE">%1$s</xliff:g>-ը"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth-ը և Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Համակարգի ՕՄ-ի կարգավորիչ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Ցուցադրել ներկառուցված մարտկոցի տոկոսայնությունը"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Ցուցադրել մարտկոցի լիցքավորման տոկոսայնությունը կարգավիճակի գոտու պատկերակի վրա, երբ այն չի լիցքավորվում"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Ընդարձակել"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Ծալել"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Փակել"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Քաշեք վար՝ փակելու համար"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Ընտրացանկ"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>-ը «Նկար նկարի մեջ» ռեժիմում է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f8604e3..66ebb86 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -492,6 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Frekuensi multinada ganda"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Aksesibilitas"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Telepon"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Dering"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Getar"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Nonaktifkan"</string>
@@ -502,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap untuk menonaktifkan."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Kontrol volume %s ditampilkan. Geser ke atas untuk menutup."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrol volume disembunyikan"</string>
+    <string name="output_title" msgid="5355078100792942802">"Keluaran media"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Keluaran panggilan telepon"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Perangkat tidak ditemukan"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Tidak ditemukan perangkat. Coba aktifkan <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth dan Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Penyetel Antarmuka Pengguna Sistem"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Tampilkan persentase baterai yang tersemat"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Tampilkan persentase tingkat baterai dalam ikon bilah status saat tidak mengisi daya"</string>
@@ -723,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Luaskan"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalkan"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Tutup"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Seret ke bawah untuk menutup"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> adalah picture-in-picture"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 66530bd..35bf451 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Ýttu til að þagga."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s stýringar fyrir hljóðstyrk sýnilegar. Strjúktu upp til að hunsa."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Stýringar fyrir hljóðstyrk faldar"</string>
+    <string name="output_title" msgid="5355078100792942802">"Margmiðlunarúttak"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Úttak símtals"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Engin tæki fundust"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Engin tæki fundust. Prófaðu að kveikja á <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth og Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Fínstillingar kerfisviðmóts"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Sýna innfellda rafhlöðustöðu"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Sýna rafhlöðustöðuna í stöðustikunni þegar tækið er ekki í hleðslu"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Stækka"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minnka"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Loka"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Draga niður til að hunsa"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Valmynd"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> er með mynd í mynd"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index c15e4b6..fec534d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -494,9 +494,10 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Frequenza multipla dual tone"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accessibilità"</string>
-    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Suoneria"</string>
-    <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrazione"</string>
-    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Disattiva audio"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Chiamate"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Attiva suoneria"</string>
+    <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Attiva vibrazione"</string>
+    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Disattiva suoneria"</string>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tocca per riattivare l\'audio."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tocca per attivare la vibrazione. L\'audio dei servizi di accessibilità può essere disattivato."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
@@ -504,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tocca per disattivare l\'audio."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s comandi del volume mostrati. Fai scorrere verso l\'alto per ignorare."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Comandi del volume nascosti"</string>
+    <string name="output_title" msgid="5355078100792942802">"Uscita contenuti multimediali"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Uscita telefonate"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nessun dispositivo trovato"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nessun dispositivo trovato. Prova ad attivare <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth e Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Ottimizzatore UI di sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostra percentuale batteria incorporata"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostra la percentuale di carica della batteria nell\'icona della barra di stato quando non è in carica"</string>
@@ -725,6 +733,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Espandi"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Riduci a icona"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Chiudi"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"Impostazioni"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Trascina verso il basso per ignorare"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> è in Picture in picture"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index cbbffa9..276fa33 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -31,9 +31,9 @@
       <item quantity="other">‏%d מסכים ב’סקירה‘</item>
       <item quantity="one">מסך אחד ב’סקירה‘</item>
     </plurals>
-    <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"אין התראות"</string>
+    <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"אין הודעות"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"מתמשך"</string>
-    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"התראות"</string>
+    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"הודעות"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"עוצמת הסוללה נמוכה"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>. הופעלה תכונת החיסכון בסוללה."</string>
@@ -49,7 +49,7 @@
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"סיבוב אוטומטי של המסך"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"השתק"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"אוטומטי"</string>
-    <string name="status_bar_settings_notifications" msgid="397146176280905137">"התראות"</string>
+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"הודעות"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"‏Bluetooth קשור"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"הגדר שיטות קלט"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"מקלדת פיזית"</string>
@@ -166,7 +166,7 @@
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> אחוזים של סוללה."</string>
     <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"טעינת סוללה, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> אחוז."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"הגדרות מערכת"</string>
-    <string name="accessibility_notifications_button" msgid="4498000369779421892">"התראות"</string>
+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"הודעות"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"הצגת כל ההודעות"</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"נקה התראה"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"‏GPS מופעל."</string>
@@ -248,7 +248,7 @@
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏מחפש GPS"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"‏מיקום מוגדר על ידי GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"בקשות מיקום פעילות"</string>
-    <string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההתראות."</string>
+    <string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההודעות."</string>
     <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
       <item quantity="two">יש בפנים עוד <xliff:g id="NUMBER_1">%s</xliff:g> הודעות.</item>
@@ -371,7 +371,7 @@
     <string name="interruption_level_priority" msgid="6426766465363855505">"עדיפות בלבד"</string>
     <string name="interruption_level_alarms" msgid="5226306993448328896">"התראות בלבד"</string>
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"שקט\nמוחלט"</string>
-    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"התראות בעדיפות\nבלבד"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"הודעות בעדיפות\nבלבד"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"התראות\nבלבד"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"בטעינה מהירה (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
@@ -470,7 +470,7 @@
     <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"הנעילה בוטלה על ידי <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_managed" msgid="8319646760022357585">"<xliff:g id="TRUST_AGENT">%1$s</xliff:g> פועל"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"המכשיר יישאר נעול עד שתבטל את נעילתו באופן ידני"</string>
-    <string name="hidden_notifications_title" msgid="7139628534207443290">"קבל התראות מהר יותר"</string>
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"קבל הודעות מהר יותר"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"צפה בהן לפני שתבטל נעילה"</string>
     <string name="hidden_notifications_cancel" msgid="3690709735122344913">"לא, תודה"</string>
     <string name="hidden_notifications_setup" msgid="41079514801976810">"הגדר"</string>
@@ -507,6 +507,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"‏%1$s. הקש כדי להשתיק."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"‏%s פקדי עוצמת הקול גלויים. החלק כלפי מעלה כדי לסגור."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"פקדי עוצמת הקול מוסתרים"</string>
+    <string name="output_title" msgid="5355078100792942802">"פלט מדיה"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"פלט שיחת טלפון"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"לא נמצאו מכשירים"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"לא נמצאו מכשירים. יש לנסות להפעיל <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"‏Bluetooth ו-Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"הצג בשורת הסטטוס את אחוז עוצמת הסוללה"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"הצג את אחוז עוצמת הסוללה בתוך הסמל שבשורת הסטטוס כשהמכשיר אינו בטעינה"</string>
@@ -555,9 +562,9 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"בעזרת פקדים של הודעות הפעלה, תוכל להגדיר רמת חשיבות מ-0 עד 5 להודעות אפליקציה. \n\n"<b>"רמה 5"</b>" \n- הצג בראש רשימת ההודעות \n- אפשר הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 4"</b>" \n- מנע הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 3"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n\n"<b>"רמה 2"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n\n"<b>"רמה 1"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n- הסתר ממסך הנעילה ומשורת הסטטוס \n- הצג בתחתית רשימת ההודעות \n\n"<b>"רמה 0"</b>" \n- חסום את כל ההודעות מהאפליקציה"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"הודעות"</string>
     <string name="notification_channel_disabled" msgid="2139193533791840539">"לא תקבל את ההודעות האלה יותר"</string>
-    <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> קטגוריות של התראות"</string>
+    <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> קטגוריות של הודעות"</string>
     <string name="notification_default_channel_desc" msgid="2506053815870808359">"האפליקציה הזו לא תומכת בקטגוריות של הודעות"</string>
-    <string name="notification_unblockable_desc" msgid="3561016061737896906">"לא ניתן לכבות התראות של האפליקציה הזאת"</string>
+    <string name="notification_unblockable_desc" msgid="3561016061737896906">"לא ניתן לכבות הודעות של האפליקציה הזאת"</string>
     <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
       <item quantity="two">קטגוריית הודעות אחת מתוך <xliff:g id="NUMBER_1">%s</xliff:g> מאפליקציה זו</item>
       <item quantity="many">קטגוריית הודעות אחת מתוך <xliff:g id="NUMBER_1">%s</xliff:g> מאפליקציה זו</item>
@@ -736,6 +743,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"הרחב"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"מזער"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"סגור"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"גרור למטה כדי לסגור"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"תפריט"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> במצב תמונה בתוך תמונה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f840225..1cff43b 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s。タップしてミュートします。"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s の音量調節が表示されています。閉じるには、上にスワイプします。"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"音量調節を非表示にしました"</string>
+    <string name="output_title" msgid="5355078100792942802">"メディア出力"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"通話の出力"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"デバイスが見つかりません"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"デバイスが見つかりません。<xliff:g id="SERVICE">%1$s</xliff:g> をオンにしてみてください"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth と Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"システムUI調整ツール"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"内蔵電池の残量の割合を表示する"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"充電していないときには電池残量の割合をステータスバーアイコンに表示する"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"閉じる"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"下にドラッグして閉じる"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"メニュー"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>はピクチャー イン ピクチャーで表示中です"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 933a5e3..870c896 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -492,6 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"ტონალური აკრეფა"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"მარტივი წვდომა"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"ზარები"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"დარეკვა"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ვიბრაცია"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"დადუმება"</string>
@@ -502,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. შეეხეთ დასადუმებლად."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s-ის ხმის მართვის საშუალებები დამალულია. დასახურად, გადაფურცლეთ ზემოთ."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"ხმის მართვის საშუალებები დამალულია"</string>
+    <string name="output_title" msgid="5355078100792942802">"მედია გამომავალი"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"სატელეფონო ზარის გამომავალი სიგნალი"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"მოწყობილობები ვერ მოიძებნა"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"მოწყობილობები ვერ მოიძებნა. ცადეთ <xliff:g id="SERVICE">%1$s</xliff:g>-ის ჩართვა"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth და Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"სისტემის UI ტუნერი"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"ჩამაგრებული ბატარეის პროცენტის ჩვენება"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ბატარეის დონის პროცენტის ჩვენება სტატუსის ზოლის ხატულას შიგნით, როდესაც არ იტენება"</string>
@@ -723,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"გაშლა"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ჩაკეცვა"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"დახურვა"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"დასახურად ჩავლებით ჩამოიტანეთ ქვემოთ"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"მენიუ"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> იყენებს რეჟიმს „ეკრანი ეკრანში“"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a9e6ffe..c4ae759 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Дыбысын өшіру үшін түртіңіз."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s дыбысты басқару элементтері көрсетулі. Сырғыту арқылы жабыңыз."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Дыбысты басқару элементтері жасырын"</string>
+    <string name="output_title" msgid="5355078100792942802">"Meдиа шығысы"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Телефон қоңырау шығысы"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Ешқандай құрылғы табылмады"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Ешқандай құрылғы табылмады. <xliff:g id="SERVICE">%1$s</xliff:g> қосып көріңіз"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth және Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Жүйелік пайдаланушылық интерфейс тюнері"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Ендірілген батарея пайыздық шамасын көрсету"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Зарядталмай тұрғанда, күй жолағы белгішесінің ішінде батарея деңгейінің пайыздық шамасын көрсетеді"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Жаю"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Кішірейту"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Жабу"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Жабу үшін төмен қарай сүйреңіз"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Mәзір"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> \"сурет ішіндегі сурет\" режимінде"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 5819f2a..12733f1 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s ។ ចុច​ដើម្បី​បិទ​សំឡេង។"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"អង្គគ្រប់គ្រងកម្រិតសំឡេង %s បានបង្ហាញ។ អូសឡើងលើដើម្បីបដិសេធ។"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"អង្គគ្រប់គ្រងកម្រិតសំឡេងបានលាក់"</string>
+    <string name="output_title" msgid="5355078100792942802">"លទ្ធផល​មេឌៀ"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"លទ្ធផល​នៃ​ការ​ហៅ​ទូរសព្ទ"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"រកមិន​ឃើញ​ឧបករណ៍​ទេ"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"រក​មិន​ឃើញ​ឧបករណ៍​ទេ។ សាក​ល្បង​បើក <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ប៊្លូធូស"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ប៊្លូធូស និង Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"កម្មវិធីសម្រួល UI ប្រព័ន្ធ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"បង្ហាញភាគរយថាមពលថ្មដែលបានបង្កប់"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"បង្ហាញភាគរយនៃកម្រិតថាមពលថ្មនៅក្នុងរូបតំណាងរបារស្ថានភាពនៅពេលមិនសាកថ្ម"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"ពង្រីក"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"បង្រួម"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"បិទ"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"អូស​ចុះក្រោម​ដើម្បី​បដិសេធ"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"ម៉ឺនុយ"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ស្ថិតក្នុងមុខងាររូបក្នុងរូប"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 5e7e1e2..b492fd4 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ಬ್ಲೂಟೂತ್‌"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"ಡ್ಯುಯಲ್‌ ಬಹು ಟೋನ್ ಆವರ್ತನೆ"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"ಪ್ರವೇಶಿಸುವಿಕೆ"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"ಕರೆಗಳು"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"ರಿಂಗ್"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ವೈಬ್ರೇಟ್‌"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"ಮ್ಯೂಟ್"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s ವಾಲ್ಯೂಮ್ ನಿಯಂತ್ರಣಗಳನ್ನು ತೋರಿಸಲಾಗಿದೆ. ವಜಾಗೊಳಿಸಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"ವಾಲ್ಯೂಮ್ ನಿಯಂತ್ರಣಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
+    <string name="output_title" msgid="5355078100792942802">"ಮೀಡಿಯಾ ಔಟ್‌ಪುಟ್"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ಫೋನ್ ಕರೆ ಔಟ್‌ಪುಟ್"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"ಯಾವ ಸಾಧನಗಳೂ ಕಂಡುಬಂದಿಲ್ಲ"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"ಯಾವುದೇ ಸಾಧನಗಳು ಪತ್ತೆಯಾಗಿಲ್ಲ. <xliff:g id="SERVICE">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಲು ಪ್ರಯತ್ನಿಸಿ"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ಬ್ಲೂಟೂತ್‌"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"ವೈ-ಫೈ"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ಬ್ಲೂಟೂತ್ ಮತ್ತು ವೈ-ಫೈ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"ಸಿಸ್ಟಂ UI ಟ್ಯೂನರ್"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"ಎಂಬೆಡ್ ಮಾಡಲಾದ ಬ್ಯಾಟರಿ ಶೇಕಡಾ ತೋರಿಸಿ"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ಚಾರ್ಜ್ ಮಾಡದಿರುವಾಗ ಸ್ಥಿತಿ ಪಟ್ಟಿ ಐಕಾನ್ ಒಳಗೆ ಬ್ಯಾಟರಿ ಮಟ್ಟದ ಶೇಕಡಾವನ್ನು ತೋರಿಸಿ"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"ವಿಸ್ತೃತಗೊಳಿಸು"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ಕುಗ್ಗಿಸಿ"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"ಮುಚ್ಚಿ"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ವಜಾಗೊಳಿಸಲು ಕೆಳಕ್ಕೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"ಮೆನು"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ಚಿತ್ರದಲ್ಲಿನ ಚಿತ್ರದಲ್ಲಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d86c32f..7fa87ed 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. 탭하여 음소거로 설정하세요."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s 볼륨 컨트롤이 표시됩니다. 닫으려면 위로 스와이프합니다."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"볼륨 컨트롤 숨김"</string>
+    <string name="output_title" msgid="5355078100792942802">"미디어 출력"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"전화 통화 출력"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"기기를 찾을 수 없음"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"기기를 찾을 수 없습니다. <xliff:g id="SERVICE">%1$s</xliff:g>을(를) 사용 설정해 보세요"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"블루투스"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"블루투스 및 Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"시스템 UI 튜너"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"내장형 배터리 잔량 비율 표시"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"충전 중이 아닌 경우 상태 표시줄 아이콘 내에 배터리 잔량 비율 표시"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"펼치기"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"최소화"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"닫기"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"아래로 드래그하여 닫기"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"메뉴"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>에서 PIP 사용 중"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index e10e2b0..e3f1fa3 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Үнүн өчүрүү үчүн басыңыз."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s үндү башкаруу элементтери көрсөтүлгөн. Этибарга албоо үчүн өйдө серпип коюңуз."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Үндү башкаруу элементтери жашырылган"</string>
+    <string name="output_title" msgid="5355078100792942802">"Медиа түзмөк"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Телефон чалуу"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Түзмөктөр табылган жок"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Түзмөктөр табылган жок. <xliff:g id="SERVICE">%1$s</xliff:g> кызматын күйгүзүп көрүңүз"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi‑Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth жана Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Батарянын кубатнын деңгээли пайыз менен көрсөтлсүн"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Түзмөк кубаттанбай турганда, батареянын деңгээли статус тилкесинде көрүнүп турат"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Жайып көрсөтүү"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Кичирейтүү"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Жабуу"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Четке кагуу үчүн төмөн сүйрөңүз"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Меню"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> – сүрөт ичиндеги сүрөт"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 2587a20..fe262ee 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. ແຕະເພື່ອປິດສຽງ."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"ສະແດງສ່ວນຄວບຄຸມສຽງ %s ແລ້ວ. ປັດອອກຂ້າງເພື່ອປິດໄວ້."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"ເຊື່ອງສ່ວນຄວບຄຸມສຽງແລ້ວ"</string>
+    <string name="output_title" msgid="5355078100792942802">"ມີເດຍເອົ້າພຸດ"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ເອົ້າພຸດສາຍໂທອອກ"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"ບໍ່ພົບອຸປະກອນ"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"ບໍ່ພົບອຸປະກອນ. ກະລຸນາລອງເປີດ <xliff:g id="SERVICE">%1$s</xliff:g> ກ່ອນ"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth ແລະ Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"ສະ​ແດງ​ເປີ​ເຊັນ​ແບັດ​ເຕີ​ຣີ​ທີ່​ຕິດ​ມາ"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ສະ​ແດງ​ເປີ​ເຊັນ​ລະ​ດັບ​ແບັດ​ເຕີ​ຣີ​ຢູ່​ດ້ານ​ໃນ​ໄອ​ຄອນ​ແຖບ​ສະ​ຖາ​ນະ ເມື່ອ​ບໍ່​ສາກ​ຢູ່"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"ຂະຫຍາຍ"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ຫຍໍ້"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"ປິດ"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ລາກລົງເພື່ອປິດໄວ້"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"ເມນູ"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ແມ່ນເປັນການສະແດງຜົນຫຼາຍຢ່າງພ້ອມກັນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 1c97452..5530fc9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -507,6 +507,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Palieskite, kad nutildytumėte."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Rodomi „%s“ garsumo valdikliai. Perbraukite į viršų, kad atsisakytumėte."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Garsumo valdikliai paslėpti"</string>
+    <string name="output_title" msgid="5355078100792942802">"Medijos išvestis"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Telefono skambučių išvestis"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Įrenginių nerasta"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Įrenginių nerasta. Bandykite įjungti „<xliff:g id="SERVICE">%1$s</xliff:g>“"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"„Bluetooth“ ir „Wi-Fi“"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sistemos naudotojo sąsajos derinimo priemonė"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Rodyti įterptą akumuliat. įkrovos procentinę vertę"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Rodyti akumuliatoriaus įkrovos lygio procentinę vertę būsenos juostos piktogramoje, kai įrenginys nėra įkraunamas"</string>
@@ -736,6 +743,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Išskleisti"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Sumažinti"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Uždaryti"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Nuvilkite žemyn, kad atsisakytumėte"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meniu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> rodom. vaizdo vaizde"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c14eb3f..574d898 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Pieskarieties, lai izslēgtu skaņu."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Tiek rādītas %s skaļuma vadīklas. Velciet augšup, lai nerādītu."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Skaļuma vadīklas paslēptas"</string>
+    <string name="output_title" msgid="5355078100792942802">"Multivides izvade"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Tālruņa zvana izvade"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nav atrasta neviena ierīce"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nav atrasta neviena ierīce. Ieslēdziet <xliff:g id="SERVICE">%1$s</xliff:g>."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth un Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sistēmas saskarnes regulators"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Rādīt akumulatora uzlādes līmeni procentos"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Rādīt akumulatora uzlādes līmeni procentos statusa joslas ikonā, kad netiek veikta uzlāde"</string>
@@ -730,6 +737,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Izvērst"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizēt"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Aizvērt"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Velciet lejup, lai noraidītu"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Izvēlne"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ir attēlā attēlā"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e30085c..b64217d 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Допрете за да се исклучи звукот."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Прикажани се контролите за јачина на звукот на %s. Повлечете нагоре за да отфрлите."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Скриени се контролите за јачина на звукот"</string>
+    <string name="output_title" msgid="5355078100792942802">"Излез за аудиовизуелни содржини"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Излез за телефонски повик"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Не се најдени уреди"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Не се најдени уреди. Обидете се да вклучите <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth и Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Адаптер на УИ на системот"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Прикажи вграден процент на батеријата"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Прикажи процент на ниво на батеријата во внатрешноста на иконата со статусна лента кога не се полни"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Проширете"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Минимизирај"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Затвори"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Повлечете надолу за да отфрлите"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Мени"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> е во слика во слика"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 385331e..aba4260 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ബ്ലൂടൂത്ത്"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"ഡ്യുവൽ മൾട്ടി റ്റോൺ ഫ്രീക്വൻസി"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"ഉപയോഗസഹായി"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"കോളുകൾ"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"റിംഗ് ചെയ്യുക"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"വൈബ്രേറ്റ് ചെയ്യുക"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"മ്യൂട്ട് ചെയ്യുക"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s വോളിയം നിയന്ത്രണങ്ങൾ കാണിച്ചിരിക്കുന്നു. ഡിസ്മിസ് ചെയ്യുന്നതിന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്യുക."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"വോളിയം നിയന്ത്രണങ്ങൾ മറച്ചിരിക്കുന്നു"</string>
+    <string name="output_title" msgid="5355078100792942802">"മീഡിയ ഔട്ട്പുട്ട്"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ഫോൺ കോൾ ഔട്ട്പുട്ട്"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"ഉപകരണങ്ങളൊന്നും കണ്ടെത്തിയില്ല"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"ഉപകരണങ്ങളൊന്നും കണ്ടെത്തിയില്ല. <xliff:g id="SERVICE">%1$s</xliff:g> ഓണാക്കുന്നത് പരീക്ഷിക്കുക"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"വൈഫൈ"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth-ഉം വൈഫൈയും"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"സിസ്റ്റം UI ട്യൂണർ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"എംബഡ് ചെയ്‌ത ബാറ്ററി ശതമാനം കാണിക്കുക"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ചാർജ്ജുചെയ്യാതിരിക്കുമ്പോൾ സ്റ്റാറ്റസ് ബാർ ഐക്കണിൽ ബാറ്ററി ലെവൽ ശതമാനം കാണിക്കുക"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"വികസിപ്പിക്കുക"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ചെറുതാക്കുക‍"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"അവസാനിപ്പിക്കുക"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"തള്ളിക്കളയാൻ താഴേക്ക് വലിച്ചിടുക"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"മെനു"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ചിത്രത്തിനുള്ളിലെ ചിത്രത്തിലാണ്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 480956c..42bd38b 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -503,6 +503,13 @@
     <!-- no translation found for volume_dialog_accessibility_shown_message (1834631467074259998) -->
     <skip />
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Түвшний удирдлагыг нуусан"</string>
+    <string name="output_title" msgid="5355078100792942802">"Медиа гаралт"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Утасны дуудлагын гаралт"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Төхөөрөмж олдсонгүй"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Төхөөрөмж олдсонгүй. <xliff:g id="SERVICE">%1$s</xliff:g>-г асааж үзнэ үү"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth болон Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Системийн UI Тохируулагч"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Залгаатай тэжээлийн хувийг харуулах"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Тэжээлийн хувийг цэнэглээгүй байх үед статусын хэсэгт харуулна уу"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Дэлгэх"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Багасгах"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Хаах"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Хаахын тулд доош чирэх"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Цэс"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> дэлгэцэн доторх дэлгэцэд байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 8a0d661..aaf907e 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ब्लूटूथ"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"दुहेरी एकाधिक टोन वारंंवारता"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"प्रवेशयोग्यता"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"कॉल"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"रिंग करा"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"कंपन"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"म्युट करा"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. नि:शब्द करण्यासाठी टॅप करा."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s आवाज नियंत्रणे दर्शविली. डिसमिस करण्यासाठी वर स्वाइप करा."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"आवाज नियंत्रणे लपविली"</string>
+    <string name="output_title" msgid="5355078100792942802">"मीडिया आउटपुट"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"फोन कॉल आउटपुट"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"कोणतीही डिव्हाइस सापडली नाहीत"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"कोणतीही डिव्हाइस सापडली नाहीत. <xliff:g id="SERVICE">%1$s</xliff:g> चालू करून पाहा"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ब्लुटूथ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"वाय-फाय"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ब्लुटूथ आणि वाय-फाय"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"सिस्टम UI ट्युनर"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"एम्बेडेड बॅटरी टक्केवारी दर्शवा"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"चार्ज होत नसताना स्टेटस बार चिन्हामध्‍ये बॅटरी पातळी टक्केवारी दर्शवा"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करा"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"लहान करा"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"बंद करा"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"डिसमिस करण्यासाठी खाली ड्रॅग करा"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"मेनू"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> चित्रामध्ये चित्र मध्ये आहे"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index e074875..118d2c7 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Ketik untuk meredam."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s kawalan kelantangan ditunjukkan. Leret ke atas untuk mengetepikan."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kawalan kelantangan disembunyikan"</string>
+    <string name="output_title" msgid="5355078100792942802">"Output media"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Output panggilan telefon"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Tiada peranti ditemui"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Tiada peranti ditemui. Cuba hidupkan <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth dan Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Penala UI Sistem"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Tunjukkan peratusan bateri terbenam"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Tunjukkan peratusan aras bateri dalam ikon bar status semasa tidak mengecas"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Kembangkan"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimumkan"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Tutup"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Seret ke bawah untuk mengetepikan"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> terdapat dalam gambar dalam gambar"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 22375b4..faca352 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -492,6 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ဘလူးတုသ်"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"နှစ်လိုင်းပေါင်း အသံပေါင်းစုံ ကြိမ်နှုန်း"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"အများသုံးစွဲနိုင်မှု"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"ခေါ်ဆိုမှုများ"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"အသံမြည်သည်"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"တုန်ခါသည်"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"အသံတိတ်သည်"</string>
@@ -502,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s။ အသံတိတ်ရန် တို့ပါ။"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"အသံအတိုးအလျှော့ခလုတ် %s ပြသထားပါသည်။ ပယ်ရန် အပေါ်သို့ပွတ်ဆွဲပါ။"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"အသံအတိုးအလျှော့ခလုတ်များကို ဝှက်ထားပါသည်"</string>
+    <string name="output_title" msgid="5355078100792942802">"မီဒီယာ အထွက်"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ဖုန်းလိုင်း အထွက်"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"မည်သည့် စက်ပစ္စည်းမျှ မတွေ့ပါ"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"မည်သည့် စက်ပစ္စည်းမျှ မတွေ့ပါ။ <xliff:g id="SERVICE">%1$s</xliff:g> ကို ဖွင့်ကြည့်ပါ"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ဘလူးတုသ်"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi−Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ဘလူးတုသ်နှင့် Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"စနစ် UI ဖမ်းစက်"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"မြုတ်ထားသည့် ဘက်ထရီ ရာခိုင်နှုန်းကို ပြပါ"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"အားမသွင်းနေစဉ်တွင် ဘတ်ထရီအဆင့် ရာခိုင်နှုန်းကို အခြေနေပြဘား အိုင်ကွန်တွင် ပြပါ"</string>
@@ -723,6 +731,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"ချဲ့ရန်"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ချုံ့ရန်"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"ပိတ်ရန်"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"ဆက်တင်များ"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ပယ်ရန်အတွက် အောက်သို့ ပွတ်ဆွဲပါ"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"မီနူး"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> သည် တစ်ခုပေါ် တစ်ခုထပ်၍ ဖွင့်ထားသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 661df03..fbcd197 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Trykk for å slå av lyden."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Volumkontrollene for %s vises. Sveip opp for å avvise dem."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Volumkontrollene er skjult"</string>
+    <string name="output_title" msgid="5355078100792942802">"Medieutdata"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Utgang for telefonsamtaler"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Fant ingen enheter"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Fant ingen enheter. Prøv å slå på <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth og Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Vis prosent for det innebygde batteriet"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Vis batterinivåprosenten inni statusfeltikonet når du ikke lader"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Vis"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimer"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Lukk"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Dra ned for å avvise"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meny"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> er i bilde-i-bilde"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index dce9cc4..ceda3c5 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ब्लुटुथ"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"दोहोरो बहु टोनको फ्रिक्वेन्सी"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"पहुँच"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"कलहरू"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"घन्टी"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"कम्पन"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"म्युट गर्नुहोस्"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s। म्यूट गर्न ट्याप गर्नुहोस्।"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s का भोल्युम सम्बन्धी नियन्त्रणहरूलाई देखाइएको छ। खारेज गर्नका लागि स्वाइप गर्नुहोस्।"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"भोल्युम सम्बन्धी नियन्त्रणहरूलाई लुकाइयो"</string>
+    <string name="output_title" msgid="5355078100792942802">"मिडियाको आउटपुट"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"फोन कलको आउटपुट"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"कुनै पनि यन्त्र भेटिएन"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"कुनै पनि यन्त्र भेटिएन। <xliff:g id="SERVICE">%1$s</xliff:g> सक्रिय गरी हेर्नुहोस्"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ब्लुटुथ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ब्लुटुथ र Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"प्रणाली UI ट्युनर"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"इम्बेड गरिएको ब्याट्री प्रतिशत देखाउनुहोस्"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"चार्ज नगरेको बेला वस्तुस्थिति पट्टी आइकन भित्र ब्याट्री प्रतिशत स्तर देखाउनुहोस्"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत गर्नुहोस्"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"सानो बनाउनुहोस्"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"बन्द गर्नुहोस्"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"खारेज गर्न तल तान्नुहोस्"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"मेनु"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> Picture-in-picture मा छ"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ca0fa07..7139a63 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -199,7 +199,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegtuigmodus ingeschakeld."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Niet storen aan, alleen prioriteit."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Niet storen aan, totale stilte."</string>
-    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Niet storen aan, alleen alarmen."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Niet storen aan, alleen wekkers."</string>
     <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"Niet storen."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Niet storen uit."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Niet storen uitgeschakeld."</string>
@@ -215,7 +215,7 @@
     <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"Locatiemelding aan."</string>
     <string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"Locatiemelding uitgeschakeld."</string>
     <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"Locatiemelding ingeschakeld."</string>
-    <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm is ingesteld op <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Wekker is ingesteld op <xliff:g id="TIME">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"Paneel sluiten."</string>
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meer tijd."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minder tijd."</string>
@@ -265,7 +265,7 @@
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Niet storen"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Alleen prioriteit"</string>
-    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alleen alarmen"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alleen wekkers"</string>
     <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Totale stilte"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> apparaten)"</string>
@@ -348,11 +348,11 @@
     <string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Veeg naar links voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="zen_priority_introduction" msgid="1149025108714420281">"Je wordt niet gestoord door geluiden en trillingen, behalve bij alarmen, herinneringen, afspraken en specifieke bellers die je selecteert. Je kunt nog steeds alles horen wat je wilt afspelen, waaronder muziek, video\'s en games."</string>
-    <string name="zen_alarms_introduction" msgid="4934328096749380201">"Je wordt niet gestoord door geluiden en trillingen, behalve bij alarmen. Je kunt nog steeds alles horen wat je wilt afspelen, waaronder muziek, video\'s en games."</string>
+    <string name="zen_priority_introduction" msgid="1149025108714420281">"Je wordt niet gestoord door geluiden en trillingen, behalve bij wekkers, herinneringen, afspraken en specifieke bellers die je selecteert. Je kunt nog steeds alles horen wat je wilt afspelen, waaronder muziek, video\'s en games."</string>
+    <string name="zen_alarms_introduction" msgid="4934328096749380201">"Je wordt niet gestoord door geluiden en trillingen, behalve bij wekkers. Je kunt nog steeds alles horen wat je wilt afspelen, waaronder muziek, video\'s en games."</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"Aanpassen"</string>
-    <string name="zen_silence_introduction_voice" msgid="3948778066295728085">"Hiermee worden ALLE geluiden en trillingen geblokkeerd, waaronder die voor alarmen, muziek, video\'s en games. Je kunt wel nog steeds bellen."</string>
-    <string name="zen_silence_introduction" msgid="3137882381093271568">"Hiermee worden ALLE geluiden en trillingen geblokkeerd, waaronder die voor alarmen, muziek, video\'s en games."</string>
+    <string name="zen_silence_introduction_voice" msgid="3948778066295728085">"Hiermee worden ALLE geluiden en trillingen geblokkeerd, waaronder die voor wekkers, muziek, video\'s en games. Je kunt wel nog steeds bellen."</string>
+    <string name="zen_silence_introduction" msgid="3137882381093271568">"Hiermee worden ALLE geluiden en trillingen geblokkeerd, waaronder die voor wekkers, muziek, video\'s en games."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Minder urgente meldingen onderaan"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tik nog eens om te openen"</string>
@@ -365,7 +365,7 @@
     <string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Totale stilte. Hiermee worden schermlezers ook op stil gezet."</string>
     <string name="interruption_level_none" msgid="6000083681244492992">"Totale stilte"</string>
     <string name="interruption_level_priority" msgid="6426766465363855505">"Alleen prioriteit"</string>
-    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alleen alarmen"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alleen wekkers"</string>
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Totale\nstilte"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Alleen\nprioriteit"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alleen\nalarmen"</string>
@@ -487,11 +487,12 @@
     <string name="stream_system" msgid="7493299064422163147">"Systeem"</string>
     <string name="stream_ring" msgid="8213049469184048338">"Bellen"</string>
     <string name="stream_music" msgid="9086982948697544342">"Media"</string>
-    <string name="stream_alarm" msgid="5209444229227197703">"Alarm"</string>
+    <string name="stream_alarm" msgid="5209444229227197703">"Wekker"</string>
     <string name="stream_notification" msgid="2563720670905665031">"Melding"</string>
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Frequentie voor tweevoudige multitoon"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Toegankelijkheid"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Oproepen"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Bellen"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Trillen"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Dempen"</string>
@@ -502,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tik om te dempen."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Volumeknoppen van %s worden weergegeven. Veeg omhoog om te sluiten."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Volumeknoppen verborgen"</string>
+    <string name="output_title" msgid="5355078100792942802">"Media-uitvoer"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Uitvoer van telefoongesprek"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Geen apparaten gevonden"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Geen apparaten gevonden. Probeer <xliff:g id="SERVICE">%1$s</xliff:g> in te schakelen."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wifi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth en wifi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Systeem-UI-tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Percentage ingebouwde batterij weergeven"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Accupercentage weergeven in het pictogram op de statusbalk wanneer er niet wordt opgeladen"</string>
@@ -512,13 +520,13 @@
     <string name="enable_demo_mode" msgid="4844205668718636518">"Demomodus inschakelen"</string>
     <string name="show_demo_mode" msgid="2018336697782464029">"Demomodus weergeven"</string>
     <string name="status_bar_ethernet" msgid="5044290963549500128">"Ethernet"</string>
-    <string name="status_bar_alarm" msgid="8536256753575881818">"Alarm"</string>
+    <string name="status_bar_alarm" msgid="8536256753575881818">"Wekker"</string>
     <string name="status_bar_work" msgid="6022553324802866373">"Werkprofiel"</string>
     <string name="status_bar_airplane" msgid="7057575501472249002">"Vliegtuigmodus"</string>
     <string name="add_tile" msgid="2995389510240786221">"Tegel toevoegen"</string>
     <string name="broadcast_tile" msgid="3894036511763289383">"Tegel \'Uitzenden\'"</string>
-    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"U hoort je volgende alarm niet <xliff:g id="WHEN">%1$s</xliff:g> tenzij u dit voor die tijd uitschakelt"</string>
-    <string name="zen_alarm_warning" msgid="444533119582244293">"U hoort je volgende alarm niet <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g> tenzij je dit voor die tijd uitschakelt"</string>
+    <string name="zen_alarm_warning" msgid="444533119582244293">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template" msgid="3980063409350522735">"om <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="4242179982586714810">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"Snelle instellingen, <xliff:g id="TITLE">%s</xliff:g>."</string>
@@ -712,7 +720,7 @@
     <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Instellingen openen."</string>
     <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Snelle instellingen openen."</string>
     <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Snelle instellingen sluiten."</string>
-    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Alarm is ingesteld."</string>
+    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Wekker is ingesteld."</string>
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Ingelogd als <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"Geen internet."</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Details openen."</string>
@@ -723,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimaliseren"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Sluiten"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Sleep omlaag om te sluiten"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in scherm-in-scherm"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 43503d6..b141801 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ਬਲੂਟੁੱਥ"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"ਦੂਹਰੀ ਮਲਟੀ ਟੋਨ ਆਵਰਤੀ"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"ਪਹੁੰਚਯੋਗਤਾ"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"ਕਾਲਾਂ"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"ਘੰਟੀ"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"ਥਰਥਰਾਹਟ"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"ਮਿਊਟ"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s ਅਵਾਜ਼ ਕੰਟਰੋਲ ਦਿਖਾਏ ਗਏ ਹਨ। ਖਾਰਜ ਕਰਨ ਲਈ ਉੱਪਰ ਸਵਾਈਪ ਕਰੋ।"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"ਵੌਲਿਊਮ ਕੰਟਰੋਲ ਲੁਕਾਏ ਗਏ ਹਨ"</string>
+    <string name="output_title" msgid="5355078100792942802">"ਮੀਡੀਆ ਆਊਟਪੁੱਟ"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ਫ਼ੋਨ ਕਾਲ ਆਊਟਪੁੱਟ"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"ਕੋਈ ਡੀਵਾਈਸ ਨਹੀਂ ਮਿਲੇ"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"ਕੋਈ ਡੀਵਾਈਸ ਨਹੀਂ ਮਿਲੇ। <xliff:g id="SERVICE">%1$s</xliff:g> ਚਾਲੂ ਕਰਨ ਨੂੰ ਅਜ਼ਮਾਓ"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"ਬਲੂਟੁੱਥ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"ਵਾਈ-ਫਾਈ"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"ਬਲੂਟੁੱਥ ਅਤੇ ਵਾਈ-ਫਾਈ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI ਟਿਊਨਰ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"ਜੋਡ਼ੀ ਗਈ ਬੈਟਰੀ ਪ੍ਰਤਿਸ਼ਤਤਾ ਦਿਖਾਓ"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ਜਦੋਂ ਚਾਰਜ ਨਾ ਹੋ ਰਹੀ ਹੋਵੇ ਤਾਂ ਸਥਿਤੀ ਪੱਟੀ ਪ੍ਰਤੀਕ ਦੇ ਅੰਦਰ ਬੈਟਰੀ ਪੱਧਰ ਪ੍ਰਤਿਸ਼ਤਤਾ ਦਿਖਾਓ"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ਛੋਟਾ ਕਰੋ"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"ਬੰਦ ਕਰੋ"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ਖਾਰਜ ਕਰਨ ਲਈ ਹੇਠਾਂ ਘਸੀਟੋ"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"ਮੀਨੂ"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ \'ਚ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e567e6ba..4c385b7 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -507,6 +507,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Kliknij, by wyciszyć."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Wyświetlane są elementy sterowania głośnością aplikacji %s. Przesuń palcem, by odrzucić."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Elementy sterowania głośnością ukryte"</string>
+    <string name="output_title" msgid="5355078100792942802">"Wyjście multimediów"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Wyjście dla połączeń telefonicznych"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nie znaleziono urządzeń"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nie znaleziono urządzeń. Spróbuj włączyć <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth i Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Kalibrator System UI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Pokaż procent naładowania baterii"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Pokaż procent naładowania baterii w ikonie na pasku stanu, gdy telefon się nie ładuje"</string>
@@ -736,10 +743,12 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Rozwiń"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizuj"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Zamknij"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Przeciągnij w dół, by zamknąć"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"Aplikacja <xliff:g id="NAME">%s</xliff:g> działa w trybie obraz w obrazie"</string>
-    <string name="pip_notification_message" msgid="5619512781514343311">"Jeśli nie chcesz, by aplikacja <xliff:g id="NAME">%s</xliff:g> korzystała z tej funkcji, otwórz ustawienia i ją wyłącz."</string>
+    <string name="pip_notification_message" msgid="5619512781514343311">"Jeśli nie chcesz, by aplikacja <xliff:g id="NAME">%s</xliff:g> korzystała z tej funkcji, otwórz ustawienia i wyłącz ją."</string>
     <string name="pip_play" msgid="1417176722760265888">"Odtwórz"</string>
     <string name="pip_pause" msgid="8881063404466476571">"Wstrzymaj"</string>
     <string name="pip_skip_to_next" msgid="1948440006726306284">"Dalej"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 61aa901..8265895 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -387,7 +387,7 @@
     <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"Todos os apps e dados nesta sessão serão excluídos."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"Remover"</string>
     <string name="guest_wipe_session_title" msgid="6419439912885956132">"Bem-vindo, convidado."</string>
-    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Deseja continuar a sessão?"</string>
+    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Quer continuar a sessão?"</string>
     <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Recomeçar"</string>
     <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Sim, continuar"</string>
     <string name="guest_notification_title" msgid="1585278533840603063">"Usuário convidado"</string>
@@ -494,6 +494,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Multifrequência de dois tons"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Acessibilidade"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Chamadas"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Tocar"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Ignorar"</string>
@@ -504,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Toque para silenciar."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s controles de volume exibidos. Deslize para cima para dispensar."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Controles de volume ocultos"</string>
+    <string name="output_title" msgid="5355078100792942802">"Saída de mídia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Saída de chamada telefônica"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nenhum dispositivo foi encontrado"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nenhum dispositivo encontrado. Tente ativar o <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth e Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizador System UI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentagem de bateria incorporada"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostrar porcentagem de nível de bateria dentro do ícone da barra de status quando não estiver carregando"</string>
@@ -725,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Fechar"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arraste para baixo para dispensar"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> está em picture-in-picture"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 681d3e4..b676a24 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Toque para desativar o som."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Controlos de volume %s apresentados. Deslize rapidamente para cima para ignorar."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Controles de volume ocultados"</string>
+    <string name="output_title" msgid="5355078100792942802">"Saída de som multimédia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Saída de som de chamada telefónica"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nenhum dispositivo encontrado."</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nenhum dispositivo encontrado. Experimente ativar o <xliff:g id="SERVICE">%1$s</xliff:g>."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth e Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizador da interface do sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar percentagem da bateria incorporada"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostrar a percentagem do nível da bateria no ícone da barra de estado quando não estiver a carregar"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Fechar"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrastar para baixo para ignorar"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"A aplicação <xliff:g id="NAME">%s</xliff:g> está no modo de ecrã no ecrã"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 61aa901..8265895 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -387,7 +387,7 @@
     <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"Todos os apps e dados nesta sessão serão excluídos."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"Remover"</string>
     <string name="guest_wipe_session_title" msgid="6419439912885956132">"Bem-vindo, convidado."</string>
-    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Deseja continuar a sessão?"</string>
+    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Quer continuar a sessão?"</string>
     <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Recomeçar"</string>
     <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Sim, continuar"</string>
     <string name="guest_notification_title" msgid="1585278533840603063">"Usuário convidado"</string>
@@ -494,6 +494,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Multifrequência de dois tons"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Acessibilidade"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Chamadas"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Tocar"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Ignorar"</string>
@@ -504,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Toque para silenciar."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s controles de volume exibidos. Deslize para cima para dispensar."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Controles de volume ocultos"</string>
+    <string name="output_title" msgid="5355078100792942802">"Saída de mídia"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Saída de chamada telefônica"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nenhum dispositivo foi encontrado"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nenhum dispositivo encontrado. Tente ativar o <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth e Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizador System UI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentagem de bateria incorporada"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostrar porcentagem de nível de bateria dentro do ícone da barra de status quando não estiver carregando"</string>
@@ -725,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Fechar"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arraste para baixo para dispensar"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> está em picture-in-picture"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2a0744e..8168dfa 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -507,6 +507,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Atingeți pentru a dezactiva sunetul."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Comenzile de volum pentru %s sunt afișate. Glisați pentru a închide."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Comenzile de volum sunt ascunse"</string>
+    <string name="output_title" msgid="5355078100792942802">"Ieșire media"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Ieșire apel telefonic"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nu s-a găsit niciun dispozitiv"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nu s-au găsit dispozitive. Încercați să activați <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth și Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Afișați procentajul bateriei încorporat"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Afișați procentajul cu nivelul bateriei în interiorul pictogramei din bara de stare, atunci când nu se încarcă"</string>
@@ -732,6 +739,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Extindeți"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizați"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Închideți"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Trageți în jos pentru a închide"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meniu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> este în modul picture-in-picture"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ac4f5fe..9456615 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -498,6 +498,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Тональный набор"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Специальные возможности"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Вызовы"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Со звуком"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Вибрация"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Без звука"</string>
@@ -508,6 +509,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Нажмите, чтобы выключить звук."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Показаны регуляторы громкости: %s. Проведите вверх, чтобы скрыть."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Регуляторы громкости скрыты"</string>
+    <string name="output_title" msgid="5355078100792942802">"Выход мультимедиа"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Выход телефонных вызовов"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Устройств не найдено"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Устройств не найдено. Включите <xliff:g id="SERVICE">%1$s</xliff:g>."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth и Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Показывать уровень заряда батареи в процентах"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Когда устройство работает в автономном режиме, процент заряда батареи показан в строке состояния"</string>
@@ -737,6 +745,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Развернуть"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Свернуть"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Закрыть"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Чтобы закрыть, потяните вниз"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Меню"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> находится в режиме \"Картинка в картинке\""</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 12f4838..338b522 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -492,6 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"බ්ලූටූත්"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"ද්විත්ව බහු ස්වර සංඛ්‍යාතය"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"ප්‍රවේශ්‍යතාව"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"ඇමතුම්"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"නාද කරන්න"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"කම්පනය කරන්න"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"නිහඬ කරන්න"</string>
@@ -502,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s හඬ පරිමා පාලන පෙන්වයි. ඉවත දැමීමට ස්වයිප් කරන්න."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"හඩ පරිමා පාලන සඟවා ඇත"</string>
+    <string name="output_title" msgid="5355078100792942802">"මාධ්‍ය ප්‍රතිදානය"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"දුරකථන ඇමතුම් ප්‍රතිදානය"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"උපාංග හමු නොවිණි"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"උපාංග හමු නොවිණි. <xliff:g id="SERVICE">%1$s</xliff:g> ක්‍රියාත්මක කිරීම උත්සාහ කරන්න"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"බ්ලූටූත්"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"බ්ලූටූත් සහ Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"පද්ධති UI සුසරකය"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"කාවද්දන ලද බැටරි ප්‍රතිශතය පෙන්වන්න"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ආරෝපණය නොවන විට තත්ත්ව තීරු නිරූපකය ඇතුළත බැටරි මට්ටම් ප්‍රතිශතය පෙන්වන්න"</string>
@@ -723,6 +731,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"දිග හරින්න"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"කුඩා කරන්න"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"වසන්න"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"සැකසීම්"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ඉවත ලෑමට පහළට ඇදගෙන යන්න"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"මෙනුව"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> පින්තූරය-තුළ-පින්තූරය තුළ වේ"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 694695c..49415a5 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -509,6 +509,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Klepnutím vypnete zvuk."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Zobrazujú sa ovládacie prvky hlasitosti zariadenia %s. Prejdením prstom nahor to odmietnete."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Ovládacie prvky hlasitosti sú skryté"</string>
+    <string name="output_title" msgid="5355078100792942802">"Výstup médií"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Výstup telefonického hovoru"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nenašli sa žiadne zariadenia"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nenašli sa žiadne zariadenia. Skúste zapnúť službu <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth a Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Tuner používateľského rozhrania systému"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Zobraziť percentá vloženej batérie"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Percentuálne zobrazenie nabitia batérie vnútri ikony v stavovom riadku, keď neprebieha nabíjanie"</string>
@@ -738,6 +745,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbaliť"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovať"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Zavrieť"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Zrušíte presunutím nadol"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Ponuka"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je v režime obraz v obraze"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 10d0104..5ba1bb5 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -509,6 +509,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Dotaknite se, če želite izklopiti zvok."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Prikazani so ti kontrolniki za glasnost: %s. Povlecite navzgor za opustitev."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrolniki za glasnost so skriti."</string>
+    <string name="output_title" msgid="5355078100792942802">"Izhod predstavnosti"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Izhod telefonskih klicev"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Ni naprav"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Ni naprav. Poskusite vklopiti <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth in Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Uglaševalnik uporabniškega vmesnika sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Prikaži odstotek napolnjenosti vgraj. akumulatorja"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikaz odstotka napolnjenosti akumulatorja znotraj ikone v vrstici stanja, ko se ne polni"</string>
@@ -738,6 +745,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Razširi"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimiraj"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Zapri"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"Nastavitve"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Povlecite navzdol, da opustite"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meni"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je v načinu slika v sliki"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 665177f..2d1591f 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Trokit për ta çaktivizuar."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Tregohen %s kontrolle volumi. Rrëshqit lart për ta larguar."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrollet e volumit janë fshehur"</string>
+    <string name="output_title" msgid="5355078100792942802">"Dalja e pajisjes"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Dalja e telefonatës"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Nuk u gjet asnjë pajisje"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Nuk u gjet asnjë pajisje. Provo të aktivizosh <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth dhe Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Shfaq përqindjen e baterisë së integruar"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Shfaq përqindjen e nivelit të baterisë brenda ikonës së shiritit të statusit kur nuk është duke u ngarkuar."</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Zgjero"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizo"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Mbyll"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Zvarrit poshtë për të larguar"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menyja"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> është në figurë brenda figurës"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index cef0f693..99d8008 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Додирните да бисте искључили звук."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Контроле за јачину звука (%s) су приказане. Превуците нагоре да бисте их одбацили."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Контроле за јачину звука су сакривене"</string>
+    <string name="output_title" msgid="5355078100792942802">"Излаз медија"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Излаз за телефонски позив"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Није пронађен ниједан уређај"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Није пронађен ниједан уређај. Пробајте да укључите услугу <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth и Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Тјунер за кориснички интерфејс система"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Приказуј уграђени проценат батерије"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Приказивање нивоа напуњености батерије у процентима унутар иконе на статусној траци када се батерија не пуни"</string>
@@ -730,6 +737,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Прошири"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Умањи"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Затвори"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Превуците надоле да бисте одбили"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Мени"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> је слика у слици"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c8f8db4..2d267df 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tryck här om du vill stänga av ljudet."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Volymkontrollerna för %s visas. Svep uppåt för att ignorera."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Volymkontrollerna är dolda"</string>
+    <string name="output_title" msgid="5355078100792942802">"Medieuppspelning"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Utdata för samtal"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Inga enheter hittades"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Inga enheter hittades. Testa att aktivera <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth och Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Inställningar för systemgränssnitt"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Visa inbäddad batteriprocent"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Visa batterinivå i procent i statusfältsikonen när enheten inte laddas"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Utöka"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimera"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Stäng"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tryck och dra nedåt för att avvisa"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meny"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> visas i bild-i-bild"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8fa370d..71285ad 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -79,7 +79,7 @@
     <string name="usb_preference_title" msgid="6551050377388882787">"Machaguo ya uhamisho wa faili la USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Angika kama kichezaji cha maudhui (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Angika kama kamera (PTP)"</string>
-    <string name="installer_cd_button_title" msgid="2312667578562201583">"Sakinisha programu ya Kuhamisha Faili ya Android ya Mac"</string>
+    <string name="installer_cd_button_title" msgid="2312667578562201583">"Weka programu ya Kuhamisha Faili inayotumika kwenye Mac"</string>
     <string name="accessibility_back" msgid="567011538994429120">"Nyuma"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Nyumbani"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menyu"</string>
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Gusa ili usitishe."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Inaonyesha %s ya vidhibiti vya sauti. Telezesha kidole juu ili uondoe."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Imeficha vidhibiti vya sauti"</string>
+    <string name="output_title" msgid="5355078100792942802">"Vifaa vya kutoa maudhui"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Vifaa vya kutoa sauti ya simu"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Hakuna vifaa vilivyopatikana"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Hakuna vifaa vilivyopatikana. Jaribu kuwasha <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth na Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Kirekebishi cha kiolesura cha mfumo"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Onyesha asilimia ya betri iliyopachikwa"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Onyesha asilimia ya kiwango cha betri ndani ya aikoni ya sehemu ya arifa inapokuwa haichaji"</string>
@@ -724,6 +731,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Panua"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Punguza"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Funga"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"Mipangilio"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Buruta ili uondoe"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menyu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> iko katika hali ya picha ndani ya picha nyingine"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 6568381..544cd79 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"புளூடூத்"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"டூயல் டோன் மல்டி ஃப்ரீக்வென்சி"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"அணுகல்தன்மை"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"அழைப்புகள்"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"ஒலி"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"அதிர்வு"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"அமைதி"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. ஒலியடக்க, தட்டவும்."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s ஒலிக் கட்டுப்பாடுகள் காட்டப்பட்டன. நிராகரிக்க, மேலே ஸ்வைப் செய்யவும்."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"ஒலிக் கட்டுப்பாடுகள் மறைக்கப்பட்டன"</string>
+    <string name="output_title" msgid="5355078100792942802">"மீடியா வெளியீடு"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ஃபோன் அழைப்பு வெளியீடு"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"சாதனங்கள் எதுவும் இல்லை"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"சாதனங்கள் எதுவும் இல்லை. <xliff:g id="SERVICE">%1$s</xliff:g>ஐ ஆன் செய்யவும்"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"புளூடூத்"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"வைஃபை"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"புளூடூத் மற்றும் வைஃபை"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"உள்ளிணைந்த பேட்டரி சதவீதத்தைக் காட்டு"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"சார்ஜ் செய்யாத போது, நிலைப் பட்டி ஐகானின் உள்ளே பேட்டரி அளவு சதவீதத்தைக் காட்டும்"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"விரி"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"சிறிதாக்கு"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"மூடு"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"நிராகரிக்க, கீழே இழுக்கவும்"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"மெனு"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> தற்போது பிக்ச்சர்-இன்-பிக்ச்சரில் உள்ளது"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index fa7cb09..c2e0dce 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"బ్లూటూత్"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"డ్యూయల్ మల్టీ టోన్ ఫ్రీక్వెన్సీ"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"యాక్సెస్ సామర్థ్యం"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"కాల్‌లు"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"రింగ్"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"వైబ్రేట్"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"మ్యూట్"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. మ్యూట్ చేయడానికి నొక్కండి."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s వాల్యూమ్ నియంత్రణలు చూపబడ్డాయి. తీసివేయడానికి పైకి స్వైప్ చేయండి."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"వాల్యూమ్ నియంత్రణలు దాచబడ్డాయి"</string>
+    <string name="output_title" msgid="5355078100792942802">"మీడియా అవుట్‌పుట్"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"ఫోన్ కాల్ అవుట్‌పుట్"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"పరికరాలు ఏవీ కనుగొనబడలేదు"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"పరికరాలు ఏవీ కనుగొనబడలేదు. <xliff:g id="SERVICE">%1$s</xliff:g>ని ఆన్ చేసి ప్రయత్నించండి"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"బ్లూటూత్"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"బ్లూటూత్ మరియు Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"సిస్టమ్ UI ట్యూనర్"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"పొందుపరిచిన బ్యాటరీ శాతం చూపు"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ఛార్జింగ్‌లో లేనప్పుడు స్థితి పట్టీ చిహ్నం లోపల బ్యాటరీ స్థాయి శాతం చూపుతుంది"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"విస్తరింపజేయి"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"కనిష్టీకరించు"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"మూసివేయి"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"తీసివేయడానికి కిందికి లాగండి"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"మెను"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> చిత్రంలో చిత్రం రూపంలో ఉంది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d43efdd..5b31061 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s แตะเพื่อปิดเสียง"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s ตัวควบคุมระดับเสียงแสดงอยู่ เลื่อนขึ้นเพื่อปิด"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"ตัวควบคุมระดับเสียงซ่อนอยู่"</string>
+    <string name="output_title" msgid="5355078100792942802">"เอาต์พุตสื่อ"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"เอาต์พุตการโทรออก"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"ไม่พบอุปกรณ์"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"ไม่พบอุปกรณ์ ลองเปิด <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"บลูทูธ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"บลูทูธและ Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"ตัวรับสัญญาณ UI ระบบ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"แสดงเปอร์เซ็นต์ของแบตเตอรี่ในตัว"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"แสดงเปอร์เซ็นต์ของระดับแบตเตอรี่ภายในไอคอนแถบสถานะเมื่อไม่มีการชาร์จ"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"ขยาย"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ย่อเล็กสุด"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"ปิด"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ลากลงเพื่อปิด"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"เมนู"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ใช้การแสดงภาพซ้อนภาพ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 4aa9ca4..dadd57e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. I-tap upang i-mute."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Ipinapakita ang mga kontrol ng volume ng %s. Mag-swipe pataas upang i-dismiss."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Nakatago ang mga kontrol ng volume"</string>
+    <string name="output_title" msgid="5355078100792942802">"Output ng media"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Output ng tawag sa telepono"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Walang nakitang device"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Walang nakitang device. Subukang i-on ang <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth at Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Tuner ng System UI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Ipakita ang naka-embed na porsyento ng baterya"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Ipakita ang porsyento ng antas ng baterya na nasa icon ng status bar kapag nagcha-charge"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Palawakin"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"I-minimize"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Isara"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"I-drag pababa upang i-dismiss"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"Nasa picture-in-picture ang <xliff:g id="NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d028fdd..d2d8ac6 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Sesi kapatmak için dokunun."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s ses denetimleri gösteriliyor. Kapatmak için hızlıca yukarı kaydırın."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Ses denetimleri gizlendi"</string>
+    <string name="output_title" msgid="5355078100792942802">"Medya çıkışı"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Telefon çağrısı çıkışı"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Cihaz bulunamadı"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Cihaz bulunamadı. <xliff:g id="SERVICE">%1$s</xliff:g> hizmetini açmayı deneyin"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Kablosuz"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth ve Kablosuz"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sistem Arayüzü Ayarlayıcısı"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Yerleşik pil yüzdesini göster"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Şarj olmazken durum çubuğu simgesinin içinde pil düzeyi yüzdesini göster"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Genişlet"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Simge durumuna getir"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Kapat"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Kapatmak için aşağıya sürükleyin"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menü"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>, pencere içinde pencere özelliğini kullanıyor"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 8fa1b72..23db95b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -498,6 +498,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Двотональний багаточастотний аналоговий сигнал"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Спеціальні можливості"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Виклики"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Дзвінок"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Вібросигнал"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Без звуку"</string>
@@ -508,6 +509,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Торкніться, щоб вимкнути звук."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Показано регуляторів гучності: %s. Проведіть пальцем угору, щоб закрити."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Регулятори гучності сховано"</string>
+    <string name="output_title" msgid="5355078100792942802">"Вивід медіа-вмісту"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Вивід телефонного виклику"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Пристроїв не знайдено"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Пристроїв не знайдено. Увімкніть <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth і Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Показувати заряд акумулятора у відсотках"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Показувати заряд акумулятора у відсотках в рядку стану, коли пристрій не заряджається"</string>
@@ -737,6 +745,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Розгорнути"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Згорнути"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Закрити"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Перетягніть униз, щоб закрити"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Меню"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"У додатку <xliff:g id="NAME">%s</xliff:g> є функція \"Картинка в картинці\""</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 73fd5886..ad5ac98 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"بلوٹوتھ"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"دوہری ملٹی ٹون فریکوئنسی"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"ایکسیسبیلٹی"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"کالز"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"رِنگ کریں"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"وائبریٹ"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"خاموش کریں"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"‏%s والیوم کے کنٹرولز دکھائے جا رہے ہیں۔ برخاست کرنے کیلئے سوائپ کریں۔"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"والیوم کے کنٹرولز مخفی ہیں"</string>
+    <string name="output_title" msgid="5355078100792942802">"میڈیا آؤٹ پٹ"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"فون کال کا آؤٹ پٹ"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"کوئی آلہ نہیں ملا"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"کوئی آلہ نہیں ملا۔ <xliff:g id="SERVICE">%1$s</xliff:g> آن کر کے آزمائیں"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"بلوٹوتھ"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"‏بلوٹوتھ اور Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"‏سسٹم UI ٹیونر"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"سرایت کردہ بیٹری کی فیصد دکھائیں"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"جب چارج نہ ہو رہا ہو تو بیٹری کی سطح کی فیصد اسٹیٹس بار آئیکن کے اندر دکھائیں"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"پھیلائیں"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"چھوٹی کریں"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"بند کریں"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"برخاست کرنے کیلئے نیچے گھسیٹیں"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"مینو"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> تصویر میں تصویر میں ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 55eb4fb..0db8ef2 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Ovozsiz qilish uchun ustiga bosing."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Ovoz balandligini boshqarish tugmalari ko‘rsatilgan: %s. Yopish uchun tepaga suring."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Ovoz balandligini boshqarish tugmalari yashirilgan"</string>
+    <string name="output_title" msgid="5355078100792942802">"Media chiqishi"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Telefon chaqiruvlari"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Hech qanday qurilma topilmadi"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Hech qanday qurilma topilmadi. <xliff:g id="SERVICE">%1$s</xliff:g> aloqasini yoqing."</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth va Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"SystemUI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Batareya foizini chiqarish"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Quvvat olmayotgan vaqtda batareya foizi holat qatorida chiqib turadi"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Yoyish"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Yig‘ish"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Yopish"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Yopish uchun pastga torting"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menyu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> tasvir ustida tasvir rejimida"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 551decf..75b18ca 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -505,6 +505,13 @@
     <!-- no translation found for volume_dialog_accessibility_shown_message (1834631467074259998) -->
     <skip />
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Các điều khiển âm lượng bị ẩn"</string>
+    <string name="output_title" msgid="5355078100792942802">"Đầu ra phương tiện"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Đầu ra cuộc gọi điệnt thoại"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Không tìm thấy thiết bị nào"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Không tìm thấy thiết bị nào. Hãy thử bật <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth và Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Bộ điều hướng giao diện người dùng hệ thống"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Hiển thị tỷ lệ phần trăm pin được nhúng"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Hiển thị tỷ lệ phần trăm mức pin bên trong biểu tượng thanh trạng thái khi không sạc"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Mở rộng"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Thu nhỏ"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Đóng"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Kéo xuống để loại bỏ"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> đang ở chế độ ảnh trong ảnh"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 2b64d86..16161ee 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -492,8 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"蓝牙"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"双音多频"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"无障碍"</string>
-    <!-- no translation found for ring_toggle_title (3281244519428819576) -->
-    <skip />
+    <string name="ring_toggle_title" msgid="3281244519428819576">"通话"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"响铃"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"振动"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"静音"</string>
@@ -504,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s。点按即可设为静音。"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"已显示%s音量控件。向上滑动即可关闭。"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"已隐藏音量控件"</string>
+    <string name="output_title" msgid="5355078100792942802">"媒体输出"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"通话输出"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"未找到任何设备"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"未找到任何设备。请尝试开启<xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"蓝牙"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"WLAN"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"蓝牙和 WLAN"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"系统界面调节工具"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"嵌入式显示电池电量百分比 显示嵌入的电池电量百分比"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"未充电时在状态栏图标内显示电池电量百分比"</string>
@@ -725,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"展开"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"关闭"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"向下拖动即可关闭"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"菜单"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>目前位于“画中画”中"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 382425d..e0ab7e4 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -505,6 +505,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s。輕按即可設為靜音。"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"已顯示 %s 音量控制項。向上快速滑動即可關閉。"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"已隱藏音量控制"</string>
+    <string name="output_title" msgid="5355078100792942802">"媒體輸出"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"通話輸出"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"找不到裝置"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"找不到裝置,請嘗試開啟<xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"藍牙"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"藍牙和 Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"系統使用者介面調諧器"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"顯示嵌入的電池百分比"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"非充電時,在狀態列圖示顯示電量百分比"</string>
@@ -726,6 +733,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"關閉"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"向下拖曳即可關閉"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"選單"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"「<xliff:g id="NAME">%s</xliff:g>」目前在畫中畫模式"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index ef9ea43..2d43da8 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -503,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s。輕觸即可設為靜音。"</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"已顯示 %s 個音量控制項。向上滑動即可關閉。"</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"已隱藏音量控制項"</string>
+    <string name="output_title" msgid="5355078100792942802">"媒體輸出"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"通話輸出"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"找不到裝置"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"找不到裝置,請嘗試開啟「<xliff:g id="SERVICE">%1$s</xliff:g>」"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"藍牙"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"藍牙和 Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"系統使用者介面調整精靈"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"顯示嵌入式電池百分比"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"未充電時在狀態列圖示中顯示電量百分比"</string>
@@ -724,6 +731,8 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"關閉"</string>
+    <!-- no translation found for pip_phone_settings (8080777499521528521) -->
+    <skip />
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"向下拖曳即可關閉"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"選單"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"「<xliff:g id="NAME">%s</xliff:g>」目前在子母畫面中"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index b3b26dc..e5bd3a9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -492,6 +492,7 @@
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"I-Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Ifrikhwensi yethoni engakuningi"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Ukufinyeleleka"</string>
+    <string name="ring_toggle_title" msgid="3281244519428819576">"Amakholi"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Khalisa"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Dlidlizela"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Thulisa"</string>
@@ -502,6 +503,13 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Thepha ukuze uthulise."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s izilawuli zevolumu ziyaboniswa. Swayiphela phezulu ukuze ulahle."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Izilawuli zevolumi zifihliwe"</string>
+    <string name="output_title" msgid="5355078100792942802">"Okukhiphayo kwemidiya"</string>
+    <string name="output_calls_title" msgid="8717692905017206161">"Okukhiphayo kwekholi yefoni"</string>
+    <string name="output_none_found" msgid="5544982839808921091">"Awekho amadivayisi atholiwe"</string>
+    <string name="output_none_found_service_off" msgid="8631969668659757069">"Awekho amadivayisi atholiwe. Zama ukuvula i-<xliff:g id="SERVICE">%1$s</xliff:g>"</string>
+    <string name="output_service_bt" msgid="6224213415445509542">"I-Bluetooth"</string>
+    <string name="output_service_wifi" msgid="3749735218931825054">"I-Wi-Fi"</string>
+    <string name="output_service_bt_wifi" msgid="4486837869988770896">"I-Bluetooth ne-Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Isishuni se-UI yesistimu"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Bonisa amaphesenti ebhethri elinamathiselwe"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Bonisa amaphesenti eleveli yebhethri ngaphakathi kwesithonjana sebha yesimo uma kungashajwa"</string>
@@ -723,6 +731,7 @@
     <string name="pip_phone_expand" msgid="5889780005575693909">"Nweba"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Nciphisa"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Vala"</string>
+    <string name="pip_phone_settings" msgid="8080777499521528521">"Izilungiselelo"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Hudulela phansi ukuze ucashise"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Imenyu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"U-<xliff:g id="NAME">%s</xliff:g> ungaphakathi kwesithombe esiphakathi kwesithombe"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f244d88..f5be337 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -143,6 +143,9 @@
 
     <color name="remote_input_accent">#eeeeee</color>
 
+    <color name="quick_step_track_background_dark">#61000000</color>
+    <color name="quick_step_track_background_light">#4DFFFFFF</color>
+
     <!-- Keyboard shortcuts colors -->
     <color name="ksh_application_group_color">#fff44336</color>
     <color name="ksh_keyword_color">#d9000000</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 60e9ebf..39ed08e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -78,10 +78,10 @@
     <dimen name="status_bar_connected_device_bt_indicator_size">17dp</dimen>
 
     <!-- Height of a small notification in the status bar-->
-    <dimen name="notification_min_height">100dp</dimen>
+    <dimen name="notification_min_height">106dp</dimen>
 
     <!-- Increased height of a small notification in the status bar -->
-    <dimen name="notification_min_height_increased">140dp</dimen>
+    <dimen name="notification_min_height_increased">146dp</dimen>
 
     <!-- Height of a small notification in the status bar which was used before android N -->
     <dimen name="notification_min_height_legacy">64dp</dimen>
@@ -90,7 +90,7 @@
     <dimen name="notification_min_height_before_p">92dp</dimen>
 
     <!-- Height of a large notification in the status bar -->
-    <dimen name="notification_max_height">292dp</dimen>
+    <dimen name="notification_max_height">294dp</dimen>
 
     <!-- Height of an ambient notification on ambient display -->
     <dimen name="notification_ambient_height">400dp</dimen>
@@ -102,16 +102,13 @@
     <dimen name="notification_max_heads_up_height_before_p">148dp</dimen>
 
     <!-- Height of a heads up notification in the status bar -->
-    <dimen name="notification_max_heads_up_height">156dp</dimen>
+    <dimen name="notification_max_heads_up_height">162dp</dimen>
 
     <!-- Height of a heads up notification in the status bar -->
     <dimen name="notification_max_heads_up_height_increased">188dp</dimen>
 
     <!-- Side padding on the lockscreen on the side of notifications -->
-    <dimen name="notification_lockscreen_side_paddings">8dp</dimen>
-
-    <!-- Additional side padding for custom content if the app doesn't target P yet -->
-    <dimen name="notification_content_custom_view_side_padding">@dimen/notification_lockscreen_side_paddings</dimen>
+    <dimen name="notification_side_paddings">4dp</dimen>
 
     <!-- Height of a messaging notifications with actions at least. Not that this is an upper bound
          and the notification won't use this much, but is measured with wrap_content -->
@@ -127,7 +124,7 @@
     <dimen name="notification_min_interaction_height">40dp</dimen>
 
     <!-- the padding of the shelf icon container -->
-    <dimen name="shelf_icon_container_padding">21dp</dimen>
+    <dimen name="shelf_icon_container_padding">13dp</dimen>
 
     <!-- The padding of a notification icon on top to the start of the notification. Used for custom
          views where the distance can't be measured -->
@@ -148,6 +145,12 @@
     <!-- The space around a notification menu item  -->
     <dimen name="notification_menu_icon_padding">20dp</dimen>
 
+    <!-- The veritical space around the buttons in the inline settings -->
+    <dimen name="notification_guts_button_spacing">20dp</dimen>
+
+    <!-- The height of the header in inline settings -->
+    <dimen name="notification_guts_header_height">24dp</dimen>
+
     <!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
     <dimen name="snooze_snackbar_min_height">56dp</dimen>
 
@@ -232,7 +235,7 @@
     <dimen name="qs_footer_height">48dp</dimen>
 
     <!-- The padding between the notifications and the quick settings container -->
-    <dimen name="qs_notification_keyguard_padding">8dp</dimen>
+    <dimen name="qs_notification_padding">@dimen/notification_side_paddings</dimen>
 
     <!-- Height of the status bar header bar when expanded -->
     <dimen name="status_bar_header_height_expanded">124dp</dimen>
@@ -385,9 +388,6 @@
          group. -->
     <dimen name="notification_children_container_divider_height">@dimen/notification_divider_height</dimen>
 
-    <!-- The height of the header for a container containing child notifications. -->
-    <dimen name="notification_children_container_header_height">53dp</dimen>
-
     <!-- The top margin for the notification children container in its non-expanded form. -->
     <dimen name="notification_children_container_margin_top">@*android:dimen/notification_content_margin_top</dimen>
 
@@ -579,6 +579,7 @@
     <dimen name="keyguard_affordance_icon_width">24dp</dimen>
 
     <dimen name="keyguard_indication_margin_bottom">65dp</dimen>
+    <dimen name="keyguard_indication_margin_bottom_ambient">30dp</dimen>
 
     <!-- The text size for battery level -->
     <dimen name="battery_level_text_size">12sp</dimen>
@@ -870,6 +871,8 @@
     <dimen name="rounded_corner_radius">0dp</dimen>
     <dimen name="rounded_corner_content_padding">0dp</dimen>
     <dimen name="nav_content_padding">0dp</dimen>
+    <dimen name="nav_quick_scrub_track_edge_padding">32dp</dimen>
+    <dimen name="nav_quick_scrub_track_thickness">2dp</dimen>
 
     <!-- Intended corner radius when drawing the mobile signal -->
     <dimen name="stat_sys_mobile_signal_corner_radius">0.75dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index dd31365..fed97c5 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -86,10 +86,6 @@
     <item type="id" name="top_roundess_animator_start_tag"/>
     <item type="id" name="top_roundess_animator_end_tag"/>
 
-    <item type="id" name="side_padding_animator_tag"/>
-    <item type="id" name="side_padding_animator_start_tag"/>
-    <item type="id" name="side_padding_animator_end_tag"/>
-
     <!-- Accessibility actions for the notification menu -->
     <item type="id" name="action_snooze_undo"/>
     <item type="id" name="action_snooze_shorter"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 98537a1..dde4dcf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -61,11 +61,26 @@
     <!-- When the battery is low, this is displayed to the user in a dialog.  The title of the low battery alert.  [CHAR LIMIT=NONE]-->
     <string name="battery_low_title">Battery is low</string>
 
+    <!-- When the battery is low and hybrid notifications are enabled, this is displayed to the user in a dialog.
+         The title of the low battery alert.  [CHAR LIMIT=NONE]-->
+    <string name="battery_low_title_hybrid">Battery is low. Turn on Battery Saver</string>
+
     <!-- A message that appears when the battery level is getting low in a dialog.  This is
-        appened to the subtitle of the low battery alert.  "percentage" is the percentage of battery
+        appended to the subtitle of the low battery alert.  "percentage" is the percentage of battery
         remaining [CHAR LIMIT=none]-->
     <string name="battery_low_percent_format"><xliff:g id="percentage">%s</xliff:g> remaining</string>
 
+    <!-- A message that appears when the battery remaining estimate is low in a dialog.  This is
+    appended to the subtitle of the low battery alert.  "percentage" is the percentage of battery
+    remaining. "time" is the amount of time remaining before the phone runs out of battery [CHAR LIMIT=none]-->
+    <string name="battery_low_percent_format_hybrid"><xliff:g id="percentage">%s</xliff:g> remaining, about <xliff:g id="time">%s</xliff:g> left based on your usage</string>
+
+    <!-- A message that appears when the battery remaining estimate is low in a dialog and insufficient
+    data was present to say it is customized to the user. This is appended to the subtitle of the
+    low battery alert.  "percentage" is the percentage of battery remaining. "time" is the amount
+     of time remaining before the phone runs out of battery [CHAR LIMIT=none]-->
+    <string name="battery_low_percent_format_hybrid_short"><xliff:g id="percentage">%s</xliff:g> remaining, about <xliff:g id="time">%s</xliff:g> left</string>
+
     <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]-->
     <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery Saver is on.</string>
 
@@ -173,22 +188,25 @@
          [CHAR LIMIT=25] -->
     <string name="compat_mode_off">Stretch to fill screen</string>
 
+    <!-- Power menu item for taking a screenshot [CHAR LIMIT=20]-->
+    <string name="global_action_screenshot">Screenshot</string>
+
     <!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] -->
     <string name="screenshot_saving_ticker">Saving screenshot\u2026</string>
     <!-- Notification title displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=50] -->
     <string name="screenshot_saving_title">Saving screenshot\u2026</string>
     <!-- Notification text displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=100] -->
-    <string name="screenshot_saving_text">Screenshot is being saved.</string>
+    <string name="screenshot_saving_text">Screenshot is being saved</string>
     <!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] -->
-    <string name="screenshot_saved_title">Screenshot captured.</string>
+    <string name="screenshot_saved_title">Screenshot saved</string>
     <!-- Notification text displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=100] -->
-    <string name="screenshot_saved_text">Tap to view your screenshot.</string>
+    <string name="screenshot_saved_text">Tap to view your screenshot</string>
     <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
-    <string name="screenshot_failed_title">Couldn\'t capture screenshot.</string>
+    <string name="screenshot_failed_title">Couldn\'t capture screenshot</string>
     <!-- Notification text displayed when we fail to save a screenshot for unknown reasons. [CHAR LIMIT=100] -->
-    <string name="screenshot_failed_to_save_unknown_text">Problem encountered while saving screenshot.</string>
+    <string name="screenshot_failed_to_save_unknown_text">Problem encountered while saving screenshot</string>
     <!-- Notification text displayed when we fail to save a screenshot. [CHAR LIMIT=100] -->
-    <string name="screenshot_failed_to_save_text">Can\'t save screenshot due to limited storage space.</string>
+    <string name="screenshot_failed_to_save_text">Can\'t save screenshot due to limited storage space</string>
     <!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
     <string name="screenshot_failed_to_capture_text">Taking screenshots isn\'t allowed by the app or
         your organization</string>
@@ -1445,38 +1463,22 @@
     <string name="notification_header_default_channel">Notifications</string>
 
     <!-- Notification Inline Controls: Shown when a channel's notifications are currently blocked -->
-    <string name="notification_channel_disabled">You won\'t get these notifications anymore</string>
+    <string name="notification_channel_disabled">You won\'t see these notifications anymore</string>
 
-    <!-- Notification: Control panel: Label that shows how many channels are included in this bundle
-        of notifications.  Replaces the channel name and only appears when there is more than one channel. -->
-    <string name="notification_num_channels"> <xliff:g id="number">%d</xliff:g> notification categories</string>
+    <!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
+    <string name="inline_keep_showing">Keep showing these notifications?</string>
 
-    <!-- Notification: Control panel: Label that shows when an app has not upgraded to use channels.
-        Hints that the user's only option is to block all of the app's notifications. -->
-    <string name="notification_default_channel_desc">This app doesn\'t have notification categories</string>
+    <!-- Notification inline controls: block notifications button -->
+    <string name="inline_stop_button">Stop notifications</string>
+
+    <!-- Notification inline controls: keep getting notifications button -->
+    <string name="inline_keep_button">Keep showing</string>
+
+    <!-- Notification Inline controls: continue receiving notifications prompt, app level -->
+    <string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
 
     <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
-    <string name="notification_unblockable_desc">Notifications from this app can\'t be turned off</string>
-
-    <!-- Notification: Control panel: Label that shows how many channels this application has
-        defined, describing the current notification channel as "1 out of n notification categories from this app". -->
-    <plurals name="notification_num_channels_desc">
-        <item quantity="one">1 out of <xliff:g id="number">%s</xliff:g> notification category from this app</item>
-        <item quantity="other">1 out of <xliff:g id="number">%s</xliff:g> notification categories from this app</item>
-    </plurals>
-
-    <!-- Notification: Control panel: For bundles of notifications, this label that lists the
-        channels used by the contained notifications.  The first two channels are listed by name,
-        followed by "and N others"
-        Example: "Friend requests, Friend confirmations"
-        Example: "Friend requests, Friend confirmations, and 1 other"
-        Example: "Friend requests, Friend confirmations, and 2 others"
-    -->
-    <string name="notification_channels_list_desc_2"><xliff:g id="channel_name_1">%1$s</xliff:g>, <xliff:g id="channel_name_2">%2$s</xliff:g></string>
-    <plurals name="notification_channels_list_desc_2_and_others">
-        <item quantity="one"><xliff:g id="channel_name_1">%1$s</xliff:g>, <xliff:g id="channel_name_2">%2$s</xliff:g>, and <xliff:g id="number">%3$d</xliff:g> other</item>
-        <item quantity="other"><xliff:g id="channel_name_1">%1$s</xliff:g>, <xliff:g id="channel_name_2">%2$s</xliff:g>, and <xliff:g id="number">%3$d</xliff:g> others</item>
-    </plurals>
+    <string name="notification_unblockable_desc">These notifications can\'t be turned off</string>
 
     <!-- Notification: Control panel: Accessibility description for expanded inline controls view, used
         to control settings about notifications related to the current notification.  -->
@@ -1488,16 +1490,15 @@
         or disable notifications from this channel -->
     <string name="notification_channel_switch_accessibility">Allow notifications from this channel</string>
     <!-- Notification: Control panel: Label for button that launches notification settings. Used
-        when this app has defined more than a single channel for notifications. -->
-    <string name="notification_all_categories">All Categories</string>
-    <!-- Notification: Control panel: Label for button that launches notification settings. Used
         when this app has only defined a single channel for notifications. -->
     <string name="notification_more_settings">More settings</string>
     <!-- Notification: Control panel: Label for a link that launches notification settings in the
         app that sent the notification. -->
-    <string name="notification_app_settings">Customize: <xliff:g id="sub_category" example="Work chats">%1$s</xliff:g></string>
+    <string name="notification_app_settings">Customize</string>
     <!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
     <string name="notification_done">Done</string>
+    <!-- Notification: inline controls: undo block button -->
+    <string name="inline_undo">Undo</string>
 
     <!-- Notification: Menu row: Content description for menu items. [CHAR LIMIT=NONE] -->
     <string name="notification_menu_accessibility"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> <xliff:g id="menu_description" example="notification controls">%2$s</xliff:g></string>
@@ -2055,4 +2056,5 @@
     <string name="touch_filtered_warning">Because an app is obscuring a permission request, Settings
         can’t verify your response.</string>
 
+
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 173a90a..64fa9c6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -22,4 +22,8 @@
 oneway interface IOverviewProxy {
     void onBind(in ISystemUiProxy sysUiProxy);
     void onMotionEvent(in MotionEvent event);
+    void onQuickSwitch();
+    void onQuickScrubStart();
+    void onQuickScrubEnd();
+    void onQuickScrubProgress(float progress);
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index a980413..d63ad08 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -280,7 +280,7 @@
     @Override
     public void showPromptReason(int reason) {
         if (reason != PROMPT_REASON_NONE) {
-            int promtReasonStringRes = getPromtReasonStringRes(reason);
+            int promtReasonStringRes = getPromptReasonStringRes(reason);
             if (promtReasonStringRes != 0) {
                 mSecurityMessageDisplay.setMessage(promtReasonStringRes);
             }
@@ -288,12 +288,12 @@
     }
 
     @Override
-    public void showMessage(String message, int color) {
+    public void showMessage(CharSequence message, int color) {
         mSecurityMessageDisplay.setNextMessageColor(color);
         mSecurityMessageDisplay.setMessage(message);
     }
 
-    protected abstract int getPromtReasonStringRes(int reason);
+    protected abstract int getPromptReasonStringRes(int reason);
 
     // Cause a VIRTUAL_KEY vibration
     public void doHapticKeyClick() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 27a3f7d..f1a5ca9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -34,6 +34,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.Utils;
 
 import java.io.File;
 
@@ -171,10 +172,14 @@
         mSecurityContainer.showPromptReason(reason);
     }
 
-    public void showMessage(String message, int color) {
+    public void showMessage(CharSequence message, int color) {
         mSecurityContainer.showMessage(message, color);
     }
 
+    public void showErrorMessage(CharSequence message) {
+        showMessage(message, Utils.getColorError(mContext));
+    }
+
     /**
      * Dismisses the keyguard by going to the next screen or making it gone.
      * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index b6184a8..ff5f5e7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -117,7 +117,7 @@
     }
 
     @Override
-    protected int getPromtReasonStringRes(int reason) {
+    protected int getPromptReasonStringRes(int reason) {
         switch (reason) {
             case PROMPT_REASON_RESTART:
                 return R.string.kg_prompt_reason_restart_password;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index d636316..cb066a1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -398,7 +398,7 @@
     }
 
     @Override
-    public void showMessage(String message, int color) {
+    public void showMessage(CharSequence message, int color) {
         mSecurityMessageDisplay.setNextMessageColor(color);
         mSecurityMessageDisplay.setMessage(message);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index c04ae68..6539ccf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -103,7 +103,7 @@
     }
 
     @Override
-    protected int getPromtReasonStringRes(int reason) {
+    protected int getPromptReasonStringRes(int reason) {
         switch (reason) {
             case PROMPT_REASON_RESTART:
                 return R.string.kg_prompt_reason_restart_pin;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 9f39321..8dc4609 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -543,8 +543,7 @@
         }
     }
 
-
-    public void showMessage(String message, int color) {
+    public void showMessage(CharSequence message, int color) {
         if (mCurrentSecuritySelection != SecurityMode.None) {
             getSecurityView(mCurrentSecuritySelection).showMessage(message, color);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 8290842..360dba3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -106,7 +106,7 @@
      * @param message the message to show
      * @param color the color to use
      */
-    void showMessage(String message, int color);
+    void showMessage(CharSequence message, int color);
 
     /**
      * Instruct the view to show usability hints, if any.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index 6012c45..a2ff8f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -139,7 +139,7 @@
     }
 
     @Override
-    public void showMessage(String message, int color) {
+    public void showMessage(CharSequence message, int color) {
         KeyguardSecurityView ksv = getSecurityView();
         if (ksv != null) {
             ksv.showMessage(message, color);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 6e0b56e..e7432ba 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -168,7 +168,7 @@
     }
 
     @Override
-    protected int getPromtReasonStringRes(int reason) {
+    protected int getPromptReasonStringRes(int reason) {
         // No message on SIM Pin
         return 0;
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 876d170..afee8ec 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -211,7 +211,7 @@
     }
 
     @Override
-    protected int getPromtReasonStringRes(int reason) {
+    protected int getPromptReasonStringRes(int reason) {
         // No message on SIM Puk
         return 0;
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 8135c61..d80a336 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -151,6 +151,7 @@
 
         mClickActions.clear();
         final int subItemsCount = subItems.size();
+        final int blendedColor = getTextColor();
 
         for (int i = 0; i < subItemsCount; i++) {
             SliceItem item = subItems.get(i);
@@ -159,7 +160,7 @@
             KeyguardSliceButton button = mRow.findViewWithTag(itemTag);
             if (button == null) {
                 button = new KeyguardSliceButton(mContext);
-                button.setTextColor(mTextColor);
+                button.setTextColor(blendedColor);
                 button.setTag(itemTag);
             } else {
                 mRow.removeView(button);
@@ -258,7 +259,7 @@
     }
 
     private void updateTextColors() {
-        final int blendedColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
+        final int blendedColor = getTextColor();
         mTitle.setTextColor(blendedColor);
         int childCount = mRow.getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -322,6 +323,10 @@
         }
     }
 
+    public int getTextColor() {
+        return ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
+    }
+
     /**
      * Representation of an item that appears under the clock on main keyguard message.
      * Shows optional separator.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 4b9a874..2873afb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -16,7 +16,6 @@
 
 package com.android.keyguard;
 
-import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -40,7 +39,6 @@
 import android.widget.TextView;
 
 import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.ChargingView;
 
 import com.google.android.collect.Sets;
 
@@ -60,7 +58,6 @@
     private View mClockSeparator;
     private TextView mOwnerInfo;
     private ViewGroup mClockContainer;
-    private ChargingView mBatteryDoze;
     private KeyguardSliceView mKeyguardSlice;
     private Runnable mPendingMarqueeStart;
     private Handler mHandler;
@@ -155,11 +152,9 @@
             mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
         }
         mOwnerInfo = findViewById(R.id.owner_info);
-        mBatteryDoze = findViewById(R.id.battery_doze);
         mKeyguardSlice = findViewById(R.id.keyguard_status_area);
         mClockSeparator = findViewById(R.id.clock_separator);
-        mVisibleInDoze = Sets.newArraySet(mBatteryDoze, mClockView, mKeyguardSlice,
-                mClockSeparator);
+        mVisibleInDoze = Sets.newArraySet(mClockView, mKeyguardSlice, mClockSeparator);
         mTextColor = mClockView.getCurrentTextColor();
 
         mKeyguardSlice.setListener(this::onSliceContentChanged);
@@ -184,10 +179,6 @@
         mClockView.setTranslationY(translation);
         mClockView.setScaleX(clockScale);
         mClockView.setScaleY(clockScale);
-        final float batteryTranslation =
-                -(mClockView.getWidth() - (mClockView.getWidth() * clockScale)) / 2;
-        mBatteryDoze.setTranslationX(batteryTranslation);
-        mBatteryDoze.setTranslationY(translation);
         mClockSeparator.setVisibility(hasHeader ? VISIBLE : GONE);
     }
 
@@ -310,7 +301,7 @@
         }
     }
 
-    public void setDark(float darkAmount) {
+    public void setDarkAmount(float darkAmount) {
         if (mDarkAmount == darkAmount) {
             return;
         }
@@ -331,7 +322,6 @@
 
         final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount);
         updateDozeVisibleViews();
-        mBatteryDoze.setDark(dark);
         mKeyguardSlice.setDark(darkAmount);
         mClockView.setTextColor(blendedTextColor);
         mClockSeparator.setBackgroundColor(blendedTextColor);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2058f15..e58ad05 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -372,6 +372,11 @@
         }
     }
 
+    @Override
+    public void onTrustError(CharSequence message) {
+        dispatchErrorMessage(message);
+    }
+
     protected void handleSimSubscriptionInfoChanged() {
         if (DEBUG_SIM_STATES) {
             Log.v(TAG, "onSubscriptionInfoChanged()");
@@ -706,6 +711,15 @@
         return mScreenOn;
     }
 
+    private void dispatchErrorMessage(CharSequence message) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onTrustAgentErrorMessage(message);
+            }
+        }
+    }
+
     static class DisplayClientState {
         public int clientGeneration;
         public boolean clearing;
@@ -1599,11 +1613,10 @@
         }
     }
 
-    private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
+    private boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
         final boolean nowPluggedIn = current.isPluggedIn();
         final boolean wasPluggedIn = old.isPluggedIn();
-        final boolean stateChangedWhilePluggedIn =
-            wasPluggedIn == true && nowPluggedIn == true
+        final boolean stateChangedWhilePluggedIn = wasPluggedIn && nowPluggedIn
             && (old.status != current.status);
 
         // change in plug state is always interesting
@@ -1616,6 +1629,11 @@
             return true;
         }
 
+        // change in battery level while keyguard visible
+        if (mKeyguardIsVisible && old.level != current.level) {
+            return true;
+        }
+
         // change where battery needs charging
         if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
             return true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 8d55eea..1afcca6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -17,13 +17,14 @@
 
 import android.app.admin.DevicePolicyManager;
 import android.graphics.Bitmap;
+import android.hardware.fingerprint.FingerprintManager;
 import android.media.AudioManager;
 import android.os.SystemClock;
-import android.hardware.fingerprint.FingerprintManager;
 import android.telephony.TelephonyManager;
 import android.view.WindowManagerPolicyConstants;
 
 import com.android.internal.telephony.IccCardConstants;
+import com.android.systemui.statusbar.KeyguardIndicationController;
 
 /**
  * Callback for general information relevant to lock screen.
@@ -271,4 +272,15 @@
      * @param dreaming true if the dream's window has been created and is visible
      */
     public void onDreamingStateChanged(boolean dreaming) { }
+
+    /**
+     * Called when an error message needs to be presented on the keyguard.
+     * Message will be visible briefly, and might be overridden by other keyguard events,
+     * like fingerprint authentication errors.
+     *
+     * @param message Message that indicates an error.
+     * @see KeyguardIndicationController.BaseKeyguardCallback#HIDE_DELAY_MS
+     * @see KeyguardIndicationController#showTransientIndication(CharSequence)
+     */
+    public void onTrustAgentErrorMessage(CharSequence message) { }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index eff84c6..5c68123 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -99,4 +99,10 @@
      * Invoked when the secondary display showing a keyguard window changes.
      */
     void onSecondaryDisplayShowingChanged(int displayId);
+
+    /**
+     * Consumes a message that was enqueued to be displayed on the next time the bouncer shows up.
+     * @return Message that should be displayed above the challenge.
+     */
+    CharSequence consumeCustomMessage();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ChargingView.java b/packages/SystemUI/src/com/android/systemui/ChargingView.java
deleted file mode 100644
index 33f8b06..0000000
--- a/packages/SystemUI/src/com/android/systemui/ChargingView.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-
-/**
- * A view that only shows its drawable while the phone is charging.
- *
- * Also reloads its drawable upon density changes.
- */
-public class ChargingView extends ImageView implements
-        BatteryController.BatteryStateChangeCallback,
-        ConfigurationController.ConfigurationListener {
-
-    private static final long CHARGING_INDICATION_DELAY_MS = 1000;
-
-    private final AmbientDisplayConfiguration mConfig;
-    private final Runnable mClearSuppressCharging = this::clearSuppressCharging;
-    private BatteryController mBatteryController;
-    private int mImageResource;
-    private boolean mCharging;
-    private boolean mDark;
-    private boolean mSuppressCharging;
-
-
-    private void clearSuppressCharging() {
-        mSuppressCharging = false;
-        removeCallbacks(mClearSuppressCharging);
-        updateVisibility();
-    }
-
-    public ChargingView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-
-        mConfig = new AmbientDisplayConfiguration(context);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.src});
-        int srcResId = a.getResourceId(0, 0);
-
-        if (srcResId != 0) {
-            mImageResource = srcResId;
-        }
-
-        a.recycle();
-
-        updateVisibility();
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mBatteryController = Dependency.get(BatteryController.class);
-        mBatteryController.addCallback(this);
-        Dependency.get(ConfigurationController.class).addCallback(this);
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mBatteryController.removeCallback(this);
-        Dependency.get(ConfigurationController.class).removeCallback(this);
-        removeCallbacks(mClearSuppressCharging);
-    }
-
-    @Override
-    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-        boolean startCharging = charging && !mCharging;
-        if (startCharging && deviceWillWakeUpWhenPluggedIn() && mDark) {
-            // We're about to wake up, and thus don't want to show the indicator just for it to be
-            // hidden again.
-            clearSuppressCharging();
-            mSuppressCharging = true;
-            postDelayed(mClearSuppressCharging, CHARGING_INDICATION_DELAY_MS);
-        }
-        mCharging = charging;
-        updateVisibility();
-    }
-
-    private boolean deviceWillWakeUpWhenPluggedIn() {
-        boolean plugTurnsOnScreen = getResources().getBoolean(
-                com.android.internal.R.bool.config_unplugTurnsOnScreen);
-        boolean aod = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
-        return !aod && plugTurnsOnScreen;
-    }
-
-    @Override
-    public void onDensityOrFontScaleChanged() {
-        setImageResource(mImageResource);
-    }
-
-    public void setDark(boolean dark) {
-        mDark = dark;
-        if (!dark) {
-            clearSuppressCharging();
-        }
-        updateVisibility();
-    }
-
-    private void updateVisibility() {
-        setVisibility(mCharging && !mSuppressCharging && mDark ? VISIBLE : INVISIBLE);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index e7e70af..7403ddc 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -40,6 +40,8 @@
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.PluginManagerImpl;
 import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.power.EnhancedEstimates;
+import com.android.systemui.power.EnhancedEstimatesImpl;
 import com.android.systemui.power.PowerNotificationWarnings;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
@@ -310,6 +312,8 @@
 
         mProviders.put(OverviewProxyService.class, () -> new OverviewProxyService(mContext));
 
+        mProviders.put(EnhancedEstimates.class, () -> new EnhancedEstimatesImpl());
+
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java b/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java
index 6aa465c..5d2e4d0 100644
--- a/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java
+++ b/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java
@@ -16,19 +16,14 @@
 
 package com.android.systemui;
 
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
 import android.content.Context;
-import android.database.ContentObserver;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.Region;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.view.DisplayCutout;
 import android.view.Gravity;
 import android.view.View;
@@ -37,25 +32,35 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 
-import java.util.Collections;
-import java.util.List;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
 /**
  * Emulates a display cutout by drawing its shape in an overlay as supplied by
  * {@link DisplayCutout}.
  */
-public class EmulatedDisplayCutout extends SystemUI {
+public class EmulatedDisplayCutout extends SystemUI implements ConfigurationListener {
     private View mOverlay;
     private boolean mAttached;
     private WindowManager mWindowManager;
 
     @Override
     public void start() {
+        Dependency.get(ConfigurationController.class).addCallback(this);
+
         mWindowManager = mContext.getSystemService(WindowManager.class);
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.EMULATE_DISPLAY_CUTOUT),
-                false, mObserver, UserHandle.USER_ALL);
-        mObserver.onChange(false);
+        updateAttached();
+    }
+
+    @Override
+    public void onOverlayChanged() {
+        updateAttached();
+    }
+
+    private void updateAttached() {
+        boolean shouldAttach = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
+        setAttached(shouldAttach);
     }
 
     private void setAttached(boolean attached) {
@@ -87,23 +92,12 @@
                 PixelFormat.TRANSLUCENT);
         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS
                 | WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
-        lp.flags2 |= WindowManager.LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
+        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         lp.setTitle("EmulatedDisplayCutout");
         lp.gravity = Gravity.TOP;
         return lp;
     }
 
-    private ContentObserver mObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
-        @Override
-        public void onChange(boolean selfChange) {
-            boolean emulateCutout = Settings.Global.getInt(
-                    mContext.getContentResolver(), Settings.Global.EMULATE_DISPLAY_CUTOUT,
-                    Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF)
-                    != Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF;
-            setAttached(emulateCutout);
-        }
-    };
-
     private static class CutoutView extends View {
         private final Paint mPaint = new Paint();
         private final Path mBounds = new Path();
@@ -114,10 +108,9 @@
 
         @Override
         public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+            mBounds.reset();
             if (insets.getDisplayCutout() != null) {
                 insets.getDisplayCutout().getBounds().getBoundaryPath(mBounds);
-            } else {
-                mBounds.reset();
             }
             invalidate();
             return insets.consumeDisplayCutout();
@@ -126,7 +119,7 @@
         @Override
         protected void onDraw(Canvas canvas) {
             if (!mBounds.isEmpty()) {
-                mPaint.setColor(Color.DKGRAY);
+                mPaint.setColor(Color.BLACK);
                 mPaint.setStyle(Paint.Style.FILL);
 
                 canvas.drawPath(mBounds, mPaint);
diff --git a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
index b15b79f..c960fa1 100644
--- a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
+++ b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui;
 
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
 import static com.android.systemui.tuner.TunablePadding.FLAG_START;
 import static com.android.systemui.tuner.TunablePadding.FLAG_END;
 
@@ -163,6 +165,7 @@
                 | WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
         lp.setTitle("RoundedOverlay");
         lp.gravity = Gravity.TOP;
+        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         return lp;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index e008148..0f34513 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -24,10 +24,12 @@
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Point;
@@ -36,7 +38,9 @@
 import android.net.ConnectivityManager;
 import android.os.Build;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
+import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
@@ -77,6 +81,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.HardwareUiLayout;
@@ -117,6 +122,7 @@
     private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
     private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
     private static final String GLOBAL_ACTION_KEY_LOGOUT = "logout";
+    private static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
 
     private final Context mContext;
     private final GlobalActionsManager mWindowManagerFuncs;
@@ -143,6 +149,7 @@
     private boolean mHasLogoutButton;
     private final boolean mShowSilentToggle;
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
+    private final ScreenshotHelper mScreenshotHelper;
 
     /**
      * @param context everything needs a context :(
@@ -183,6 +190,7 @@
                 R.bool.config_useFixedVolume);
 
         mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
+        mScreenshotHelper = new ScreenshotHelper(context);
     }
 
     /**
@@ -340,6 +348,8 @@
                 mItems.add(getAssistAction());
             } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
                 mItems.add(new RestartAction());
+            } else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
+                mItems.add(new ScreenshotAction());
             } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
                 if (mDevicePolicyManager.isLogoutEnabled()
                         && getCurrentUser().id != UserHandle.USER_SYSTEM) {
@@ -458,6 +468,38 @@
     }
 
 
+    private class ScreenshotAction extends SinglePressAction {
+        public ScreenshotAction() {
+            super(R.drawable.ic_screenshot, R.string.global_action_screenshot);
+        }
+
+        @Override
+        public void onPress() {
+            // Add a little delay before executing, to give the
+            // dialog a chance to go away before it takes a
+            // screenshot.
+            // TODO: instead, omit global action dialog layer
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    mScreenshotHelper.takeScreenshot(1, true, true, mHandler);
+                    MetricsLogger.action(mContext,
+                            MetricsEvent.ACTION_SCREENSHOT_POWER_MENU);
+                }
+            }, 500);
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+    }
+
     private class BugReportAction extends SinglePressAction implements LongPressAction {
 
         public BugReportAction() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 2a5ae0d..22b41a4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -96,9 +96,9 @@
         }
 
         @Override // Binder interface
-        public void dismiss(IKeyguardDismissCallback callback) {
+        public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
             checkPermission();
-            mKeyguardViewMediator.dismiss(callback);
+            mKeyguardViewMediator.dismiss(callback, message);
         }
 
         @Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index bd46c5f..e49e80d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -103,11 +103,12 @@
 
     @Override
     public Slice onBindSlice(Uri sliceUri) {
-        ListBuilder builder = new ListBuilder(mSliceUri)
-                .addRow(new RowBuilder(mDateUri).setTitle(mLastText));
+        ListBuilder builder = new ListBuilder(getContext(), mSliceUri);
+        builder.addRow(new RowBuilder(builder, mDateUri).setTitle(mLastText));
         if (!TextUtils.isEmpty(mNextAlarm)) {
             Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big);
-            builder.addRow(new RowBuilder(mAlarmUri).setTitle(mNextAlarm).addEndItem(icon));
+            builder.addRow(new RowBuilder(builder, mAlarmUri)
+                    .setTitle(mNextAlarm).addEndItem(icon));
         }
 
         return builder.build();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 91ae448..653e500 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -25,7 +25,6 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 
-
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.NotificationManager;
@@ -344,6 +343,7 @@
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
     private boolean mLockWhenSimRemoved;
+    private CharSequence mCustomMessage;
 
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
@@ -368,7 +368,7 @@
                     return;
                 } else if (info.isGuest() || info.isDemo()) {
                     // If we just switched to a guest, try to dismiss keyguard.
-                    dismiss(null /* callback */);
+                    dismiss(null /* callback */, null /* message */);
                 }
             }
         }
@@ -654,6 +654,13 @@
         }
 
         @Override
+        public CharSequence consumeCustomMessage() {
+            final CharSequence message = mCustomMessage;
+            mCustomMessage = null;
+            return message;
+        }
+
+        @Override
         public void onSecondaryDisplayShowingChanged(int displayId) {
             synchronized (KeyguardViewMediator.this) {
                 setShowingLocked(mShowing, displayId, false);
@@ -1321,20 +1328,22 @@
     /**
      * Dismiss the keyguard through the security layers.
      * @param callback Callback to be informed about the result
+     * @param message Message that should be displayed on the bouncer.
      */
-    private void handleDismiss(IKeyguardDismissCallback callback) {
+    private void handleDismiss(IKeyguardDismissCallback callback, CharSequence message) {
         if (mShowing) {
             if (callback != null) {
                 mDismissCallbackRegistry.addCallback(callback);
             }
+            mCustomMessage = message;
             mStatusBarKeyguardViewManager.dismissAndCollapse();
         } else if (callback != null) {
             new DismissCallbackWrapper(callback).notifyDismissError();
         }
     }
 
-    public void dismiss(IKeyguardDismissCallback callback) {
-        mHandler.obtainMessage(DISMISS, callback).sendToTarget();
+    public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
+        mHandler.obtainMessage(DISMISS, new DismissMessage(callback, message)).sendToTarget();
     }
 
     /**
@@ -1551,7 +1560,8 @@
                     }
                     break;
                 case DISMISS:
-                    handleDismiss((IKeyguardDismissCallback) msg.obj);
+                    final DismissMessage message = (DismissMessage) msg.obj;
+                    handleDismiss(message.getCallback(), message.getMessage());
                     break;
                 case START_KEYGUARD_EXIT_ANIM:
                     Trace.beginSection("KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
@@ -2161,4 +2171,22 @@
             }
         }
     }
+
+    private static class DismissMessage {
+        private final CharSequence mMessage;
+        private final IKeyguardDismissCallback mCallback;
+
+        DismissMessage(IKeyguardDismissCallback callback, CharSequence message) {
+            mCallback = callback;
+            mMessage = message;
+        }
+
+        public IKeyguardDismissCallback getCallback() {
+            return mCallback;
+        }
+
+        public CharSequence getMessage() {
+            return mMessage;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index bfe07a9..0486a9d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -373,7 +373,7 @@
             if (menuState == MENU_STATE_FULL) {
                 mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim);
             } else {
-                mMenuContainerAnimator.playTogether(settingsAnim, dismissAnim);
+                mMenuContainerAnimator.playTogether(dismissAnim);
             }
             mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
             mMenuContainerAnimator.setDuration(MENU_FADE_DURATION);
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
new file mode 100644
index 0000000..8f41a60
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
@@ -0,0 +1,8 @@
+package com.android.systemui.power;
+
+public interface EnhancedEstimates {
+
+    boolean isHybridNotificationEnabled();
+
+    Estimate getEstimate();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
new file mode 100644
index 0000000..d447542
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
@@ -0,0 +1,16 @@
+package com.android.systemui.power;
+
+import android.util.Log;
+
+public class EnhancedEstimatesImpl implements EnhancedEstimates {
+
+    @Override
+    public boolean isHybridNotificationEnabled() {
+        return false;
+    }
+
+    @Override
+    public Estimate getEstimate() {
+        return null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/Estimate.java b/packages/SystemUI/src/com/android/systemui/power/Estimate.java
new file mode 100644
index 0000000..12a8f0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/Estimate.java
@@ -0,0 +1,11 @@
+package com.android.systemui.power;
+
+public class Estimate {
+    public final long estimateMillis;
+    public final boolean isBasedOnUsage;
+
+    public Estimate(long estimateMillis, boolean isBasedOnUsage) {
+        this.estimateMillis = estimateMillis;
+        this.isBasedOnUsage = isBasedOnUsage;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index c29b362..736286f 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -17,40 +17,40 @@
 package com.android.systemui.power;
 
 import android.app.Notification;
-import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
 import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.icu.text.MeasureFormat;
+import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
 import android.media.AudioAttributes;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
-import android.os.SystemClock;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.support.annotation.VisibleForTesting;
+import android.text.format.DateUtils;
 import android.util.Slog;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
-import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.util.NotificationChannels;
 
 import java.io.PrintWriter;
 import java.text.NumberFormat;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
 
 public class PowerNotificationWarnings implements PowerUI.WarningsUI {
     private static final String TAG = PowerUI.TAG + ".Notification";
@@ -96,8 +96,9 @@
     private long mScreenOffTime;
     private int mShowing;
 
-    private long mBucketDroppedNegativeTimeMs;
+    private long mWarningTriggerTimeMs;
 
+    private Estimate mEstimate;
     private boolean mWarning;
     private boolean mPlaySound;
     private boolean mInvalidCharger;
@@ -130,14 +131,22 @@
     public void update(int batteryLevel, int bucket, long screenOffTime) {
         mBatteryLevel = batteryLevel;
         if (bucket >= 0) {
-            mBucketDroppedNegativeTimeMs = 0;
+            mWarningTriggerTimeMs = 0;
         } else if (bucket < mBucket) {
-            mBucketDroppedNegativeTimeMs = System.currentTimeMillis();
+            mWarningTriggerTimeMs = System.currentTimeMillis();
         }
         mBucket = bucket;
         mScreenOffTime = screenOffTime;
     }
 
+    @Override
+    public void updateEstimate(Estimate estimate) {
+        mEstimate = estimate;
+        if (estimate.estimateMillis <= PowerUI.THREE_HOURS_IN_MILLIS) {
+            mWarningTriggerTimeMs = System.currentTimeMillis();
+        }
+    }
+
     private void updateNotification() {
         if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning + " mPlaySound="
                 + mPlaySound + " mInvalidCharger=" + mInvalidCharger);
@@ -171,25 +180,43 @@
         mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, n, UserHandle.ALL);
     }
 
-    private void showWarningNotification() {
-        final int textRes = R.string.battery_low_percent_format;
+    protected void showWarningNotification() {
         final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0);
 
+        // get standard notification copy
+        String title = mContext.getString(R.string.battery_low_title);
+        String contentText = mContext.getString(R.string.battery_low_percent_format, percentage);
+
+        // override notification copy if hybrid notification enabled
+        if (mEstimate != null) {
+            title = mContext.getString(R.string.battery_low_title_hybrid);
+            contentText = mContext.getString(
+                    mEstimate.isBasedOnUsage
+                            ? R.string.battery_low_percent_format_hybrid
+                            : R.string.battery_low_percent_format_hybrid_short,
+                    percentage,
+                    getTimeRemainingFormatted());
+        }
+
         final Notification.Builder nb =
                 new Notification.Builder(mContext, NotificationChannels.BATTERY)
                         .setSmallIcon(R.drawable.ic_power_low)
                         // Bump the notification when the bucket dropped.
-                        .setWhen(mBucketDroppedNegativeTimeMs)
+                        .setWhen(mWarningTriggerTimeMs)
                         .setShowWhen(false)
-                        .setContentTitle(mContext.getString(R.string.battery_low_title))
-                        .setContentText(mContext.getString(textRes, percentage))
+                        .setContentTitle(title)
+                        .setContentText(contentText)
                         .setOnlyAlertOnce(true)
                         .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
-                        .setVisibility(Notification.VISIBILITY_PUBLIC)
-                        .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
+                        .setVisibility(Notification.VISIBILITY_PUBLIC);
         if (hasBatterySettings()) {
             nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
         }
+        // Make the notification red if the percentage goes below a certain amount or the time
+        // remaining estimate is disabled
+        if (mEstimate == null || mBucket < 0) {
+            nb.setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
+        }
         nb.addAction(0,
                 mContext.getString(R.string.battery_saver_start_action),
                 pendingBroadcast(ACTION_START_SAVER));
@@ -201,6 +228,23 @@
         mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, n, UserHandle.ALL);
     }
 
+    @VisibleForTesting
+    String getTimeRemainingFormatted() {
+        final Locale currentLocale = mContext.getResources().getConfiguration().getLocales().get(0);
+        MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.NARROW);
+
+        final long remainder = mEstimate.estimateMillis % DateUtils.HOUR_IN_MILLIS;
+        final long hours = TimeUnit.MILLISECONDS.toHours(
+                mEstimate.estimateMillis - remainder);
+        // round down to the nearest 15 min for now to not appear overly precise
+        final long minutes = TimeUnit.MILLISECONDS.toMinutes(
+                remainder - (remainder % TimeUnit.MINUTES.toMillis(15)));
+        final Measure hoursMeasure = new Measure(hours, MeasureUnit.HOUR);
+        final Measure minutesMeasure = new Measure(minutes, MeasureUnit.MINUTE);
+
+        return frmt.formatMeasures(hoursMeasure, minutesMeasure);
+    }
+
     private PendingIntent pendingBroadcast(String action) {
         return PendingIntent.getBroadcastAsUser(mContext,
                 0, new Intent(action), 0, UserHandle.CURRENT);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index c1a3623..c5aab60 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -52,6 +52,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
 
 public class PowerUI extends SystemUI {
     static final String TAG = "PowerUI";
@@ -59,6 +60,7 @@
     private static final long TEMPERATURE_INTERVAL = 30 * DateUtils.SECOND_IN_MILLIS;
     private static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS;
     private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer
+    static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3;
 
     private final Handler mHandler = new Handler();
     private final Receiver mReceiver = new Receiver();
@@ -68,9 +70,11 @@
     private WarningsUI mWarnings;
     private final Configuration mLastConfiguration = new Configuration();
     private int mBatteryLevel = 100;
+    private long mTimeRemaining = Long.MAX_VALUE;
     private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
     private int mPlugType = 0;
     private int mInvalidCharger = 0;
+    private EnhancedEstimates mEnhancedEstimates;
 
     private int mLowBatteryAlertCloseLevel;
     private final int[] mLowBatteryReminderLevels = new int[2];
@@ -83,8 +87,8 @@
     private long mNextLogTime;
     private IThermalService mThermalService;
 
-    // We create a method reference here so that we are guaranteed that we can remove a callback
     // by using the same instance (method references are not guaranteed to be the same object
+    // We create a method reference here so that we are guaranteed that we can remove a callback
     // each time they are created).
     private final Runnable mUpdateTempCallback = this::updateTemperatureWarning;
 
@@ -94,6 +98,7 @@
                 mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
         mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
         mWarnings = Dependency.get(WarningsUI.class);
+        mEnhancedEstimates = Dependency.get(EnhancedEstimates.class);
         mLastConfiguration.setTo(mContext.getResources().getConfiguration());
 
         ContentObserver obs = new ContentObserver(mHandler) {
@@ -131,10 +136,15 @@
                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
 
         final ContentResolver resolver = mContext.getContentResolver();
-        int defWarnLevel = mContext.getResources().getInteger(
+        final int defWarnLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
-        int warnLevel = Settings.Global.getInt(resolver,
+        final int lowPowerModeTriggerLevel = Settings.Global.getInt(resolver,
                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
+
+        // NOTE: Keep the logic in sync with BatteryService.
+        // TODO: Propagate this value from BatteryService to system UI, really.
+        int warnLevel =  Math.min(defWarnLevel, lowPowerModeTriggerLevel);
+
         if (warnLevel == 0) {
             warnLevel = defWarnLevel;
         }
@@ -231,21 +241,9 @@
                     return;
                 }
 
-                boolean isPowerSaver = mPowerManager.isPowerSaveMode();
-                if (!plugged
-                        && !isPowerSaver
-                        && (bucket < oldBucket || oldPlugged)
-                        && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
-                        && bucket < 0) {
+                // Show the correct version of low battery warning if needed
+                maybeShowBatteryWarning(plugged, oldPlugged, oldBucket, bucket);
 
-                    // only play SFX when the dialog comes up or the bucket changes
-                    final boolean playSound = bucket != oldBucket || oldPlugged;
-                    mWarnings.showLowBatteryWarning(playSound);
-                } else if (isPowerSaver || plugged || (bucket > oldBucket && bucket > 0)) {
-                    mWarnings.dismissLowBatteryWarning();
-                } else {
-                    mWarnings.updateLowBatteryWarning();
-                }
             } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                 mScreenOffTime = SystemClock.elapsedRealtime();
             } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
@@ -256,7 +254,65 @@
                 Slog.w(TAG, "unknown intent: " + intent);
             }
         }
-    };
+    }
+
+    protected void maybeShowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
+        int bucket) {
+        boolean isPowerSaver = mPowerManager.isPowerSaveMode();
+        // only play SFX when the dialog comes up or the bucket changes
+        final boolean playSound = bucket != oldBucket || oldPlugged;
+        long oldTimeRemaining = mTimeRemaining;
+        if (mEnhancedEstimates.isHybridNotificationEnabled()) {
+            final Estimate estimate = mEnhancedEstimates.getEstimate();
+            // Turbo is not always booted once SysUI is running so we have ot make sure we actually
+            // get data back
+            if (estimate != null) {
+                mTimeRemaining = estimate.estimateMillis;
+                mWarnings.updateEstimate(estimate);
+            }
+        }
+
+        if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket, oldTimeRemaining,
+                mTimeRemaining,
+                isPowerSaver, mBatteryStatus)) {
+            mWarnings.showLowBatteryWarning(playSound);
+        } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining,
+                isPowerSaver)) {
+            mWarnings.dismissLowBatteryWarning();
+        } else {
+            mWarnings.updateLowBatteryWarning();
+        }
+    }
+
+    @VisibleForTesting
+    boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
+            int bucket, long oldTimeRemaining, long timeRemaining,
+            boolean isPowerSaver, int mBatteryStatus) {
+        return !plugged
+                && !isPowerSaver
+                && (((bucket < oldBucket || oldPlugged) && bucket < 0)
+                        || (mEnhancedEstimates.isHybridNotificationEnabled()
+                                && timeRemaining < THREE_HOURS_IN_MILLIS
+                                && isHourLess(oldTimeRemaining, timeRemaining)))
+                && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN;
+    }
+
+    private boolean isHourLess(long oldTimeRemaining, long timeRemaining) {
+        final long dif = oldTimeRemaining - timeRemaining;
+        return dif >= TimeUnit.HOURS.toMillis(1);
+    }
+
+    @VisibleForTesting
+    boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket,
+            long timeRemaining, boolean isPowerSaver) {
+        final boolean hybridWouldDismiss = mEnhancedEstimates.isHybridNotificationEnabled()
+                && timeRemaining > THREE_HOURS_IN_MILLIS;
+        final boolean standardWouldDismiss = (bucket > oldBucket && bucket > 0);
+        return isPowerSaver
+                || plugged
+                || (standardWouldDismiss && (!mEnhancedEstimates.isHybridNotificationEnabled()
+                        || hybridWouldDismiss));
+    }
 
     private void initTemperatureWarning() {
         ContentResolver resolver = mContext.getContentResolver();
@@ -428,6 +484,7 @@
 
     public interface WarningsUI {
         void update(int batteryLevel, int bucket, long screenOffTime);
+        void updateEstimate(Estimate estimate);
         void dismissLowBatteryWarning();
         void showLowBatteryWarning(boolean playSound);
         void dismissInvalidChargerWarning();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 33b5268..7f0acc2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -17,13 +17,18 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Path;
 import android.graphics.Point;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.widget.FrameLayout;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.statusbar.ExpandableOutlineView;
 
 /**
  * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
@@ -31,6 +36,7 @@
 public class QSContainerImpl extends FrameLayout {
 
     private final Point mSizePoint = new Point();
+    private final Path mClipPath = new Path();
 
     private int mHeightOverride = -1;
     protected View mQSPanel;
@@ -40,6 +46,7 @@
     private QSCustomizer mQSCustomizer;
     private View mQSFooter;
     private float mFullElevation;
+    private float mRadius;
 
     public QSContainerImpl(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -54,6 +61,8 @@
         mQSCustomizer = findViewById(R.id.qs_customize);
         mQSFooter = findViewById(R.id.qs_footer);
         mFullElevation = mQSPanel.getElevation();
+        mRadius = getResources().getDimensionPixelSize(
+                Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
 
         setClickable(true);
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -93,6 +102,18 @@
         updateExpansion();
     }
 
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        boolean ret;
+        canvas.save();
+        if (child != mQSCustomizer) {
+            canvas.clipPath(mClipPath);
+        }
+        ret = super.drawChild(canvas, child, drawingTime);
+        canvas.restore();
+        return ret;
+    }
+
     /**
      * Overrides the height of this view (post-layout), so that the content is clipped to that
      * height and the background is set to that height.
@@ -110,6 +131,10 @@
         mQSDetail.setBottom(getTop() + height);
         // Pin QS Footer to the bottom of the panel.
         mQSFooter.setTranslationY(height - mQSFooter.getHeight());
+
+        ExpandableOutlineView.getRoundedRectPath(0, 0, getWidth(), height, mRadius,
+                mRadius,
+                mClipPath);
     }
 
     protected int calculateContainerHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index c249e37..0f83078 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -103,7 +103,7 @@
 
             if (iv instanceof SlashImageView) {
                 ((SlashImageView) iv).setAnimationEnabled(shouldAnimate);
-                ((SlashImageView) iv).setState(state.slash, d);
+                ((SlashImageView) iv).setState(null, d);
             } else {
                 iv.setImageDrawable(d);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 4d0e60d..acd327b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -13,7 +13,12 @@
  */
 package com.android.systemui.qs.tileimpl;
 
+import static com.android.systemui.qs.tileimpl.QSIconViewImpl.QS_ANIM_LENGTH;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
@@ -22,16 +27,21 @@
 import android.os.Message;
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
 import android.widget.Switch;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.*;
+import com.android.systemui.plugins.qs.QSIconView;
+import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 
 public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
@@ -47,6 +57,12 @@
     private boolean mCollapsedView;
     private boolean mClicked;
 
+    private final ImageView mBg;
+    private final int mColorActive;
+    private final int mColorInactive;
+    private final int mColorDisabled;
+    private int mCircleColor;
+
     public QSTileBaseView(Context context, QSIconView icon) {
         this(context, icon, false);
     }
@@ -60,6 +76,10 @@
         mIconFrame.setForegroundGravity(Gravity.CENTER);
         int size = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
         addView(mIconFrame, new LayoutParams(size, size));
+        mBg = new ImageView(getContext());
+        mBg.setScaleType(ScaleType.FIT_CENTER);
+        mBg.setImageResource(R.drawable.ic_qs_circle);
+        mIconFrame.addView(mBg);
         mIcon = icon;
         FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -73,6 +93,11 @@
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
         setBackground(mTileBackground);
 
+        mColorActive = Utils.getColorAttr(context, android.R.attr.colorAccent);
+        mColorDisabled = Utils.getDisabled(context,
+                Utils.getColorAttr(context, android.R.attr.textColorTertiary));
+        mColorInactive = Utils.getColorAttr(context, android.R.attr.textColorSecondary);
+
         setPadding(0, 0, 0, 0);
         setClipChildren(false);
         setClipToPadding(false);
@@ -80,6 +105,10 @@
         setFocusable(true);
     }
 
+    public View getBgCicle() {
+        return mBg;
+    }
+
     protected Drawable newTileBackground() {
         final int[] attrs = new int[]{android.R.attr.selectableItemBackgroundBorderless};
         final TypedArray ta = getContext().obtainStyledAttributes(attrs);
@@ -150,6 +179,20 @@
     }
 
     protected void handleStateChanged(QSTile.State state) {
+        int circleColor = getCircleColor(state.state);
+        if (circleColor != mCircleColor) {
+            if (mBg.isShown()) {
+                ValueAnimator animator = ValueAnimator.ofArgb(mCircleColor, circleColor)
+                        .setDuration(QS_ANIM_LENGTH);
+                animator.addUpdateListener(animation -> mBg.setImageTintList(ColorStateList.valueOf(
+                        (Integer) animation.getAnimatedValue())));
+                animator.start();
+            } else {
+                QSIconViewImpl.setTint(mBg, circleColor);
+            }
+            mCircleColor = circleColor;
+        }
+
         setClickable(state.state != Tile.STATE_UNAVAILABLE);
         mIcon.setIcon(state);
         setContentDescription(state.contentDescription);
@@ -163,6 +206,19 @@
         }
     }
 
+    private int getCircleColor(int state) {
+        switch (state) {
+            case Tile.STATE_ACTIVE:
+                return mColorActive;
+            case Tile.STATE_INACTIVE:
+            case Tile.STATE_UNAVAILABLE:
+                return mColorDisabled;
+            default:
+                Log.e(TAG, "Invalid state " + state);
+                return 0;
+        }
+    }
+
     @Override
     public void setClickable(boolean clickable) {
         super.setClickable(clickable);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 576a447..72592829 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -373,11 +373,11 @@
         switch (state) {
             case Tile.STATE_UNAVAILABLE:
                 return Utils.getDisabled(context,
-                        Utils.getColorAttr(context, android.R.attr.colorForeground));
+                        Utils.getColorAttr(context, android.R.attr.textColorSecondary));
             case Tile.STATE_INACTIVE:
-                return Utils.getColorAttr(context, android.R.attr.textColorHint);
+                return Utils.getColorAttr(context, android.R.attr.textColorSecondary);
             case Tile.STATE_ACTIVE:
-                return Utils.getColorAttr(context, android.R.attr.textColorPrimary);
+                return Utils.getColorAttr(context, android.R.attr.colorPrimary);
             default:
                 Log.e("QSTile", "Invalid state " + state);
                 return 0;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index f3bae20..34b8bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -67,6 +67,8 @@
                 case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
                     mScreenshot.takeScreenshotPartial(finisher, msg.arg1 > 0, msg.arg2 > 0);
                     break;
+                default:
+                    Log.d(TAG, "Invalid screenshot option: " + msg.what);
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index ff0357a..e59c703 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -931,13 +931,6 @@
     }
 
     @Override
-    public void setCurrentSidePaddings(float currentSidePaddings) {
-        super.setCurrentSidePaddings(currentSidePaddings);
-        mBackgroundNormal.setCurrentSidePaddings(currentSidePaddings);
-        mBackgroundDimmed.setCurrentSidePaddings(currentSidePaddings);
-    }
-
-    @Override
     protected boolean childNeedsClipping(View child) {
         if (child instanceof NotificationBackgroundView && isClippingNeeded()) {
             return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index f53eb48..d1e6dcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -2362,16 +2362,15 @@
             NotificationContentView contentView = (NotificationContentView) child;
             if (isClippingNeeded()) {
                 return true;
-            } else if (!hasNoRoundingAndNoPadding() && contentView.shouldClipToSidePaddings()) {
+            } else if (!hasNoRounding() && contentView.shouldClipToRounding()) {
                 return true;
             }
         } else if (child == mChildrenContainer) {
-            if (isClippingNeeded() || ((isGroupExpanded() || isGroupExpansionChanging())
-                    && getClipBottomAmount() != 0.0f && getCurrentBottomRoundness() != 0.0f)) {
+            if (isClippingNeeded() || !hasNoRounding()) {
                 return true;
             }
         } else if (child instanceof NotificationGuts) {
-            return !hasNoRoundingAndNoPadding();
+            return !hasNoRounding();
         }
         return super.childNeedsClipping(child);
     }
@@ -2401,9 +2400,8 @@
         return super.getCustomClipPath(child);
     }
 
-    private boolean hasNoRoundingAndNoPadding() {
-        return mCurrentSidePaddings == 0 && getCurrentBottomRoundness() == 0.0f
-                && getCurrentTopRoundness() == 0.0f;
+    private boolean hasNoRounding() {
+        return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
     }
 
     public boolean isShowingAmbient() {
@@ -2418,20 +2416,6 @@
         }
     }
 
-    @Override
-    public void setCurrentSidePaddings(float currentSidePaddings) {
-        if (mIsSummaryWithChildren) {
-            List<ExpandableNotificationRow> notificationChildren =
-                    mChildrenContainer.getNotificationChildren();
-            int size = notificationChildren.size();
-            for (int i = 0; i < size; i++) {
-                ExpandableNotificationRow row = notificationChildren.get(i);
-                row.setCurrentSidePaddings(currentSidePaddings);
-            }
-        }
-        super.setCurrentSidePaddings(currentSidePaddings);
-    }
-
     public static class NotificationViewState extends ExpandableViewState {
 
         private final StackScrollState mOverallState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index db19d2f..66b3a75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -58,6 +58,7 @@
     private static final Path EMPTY_PATH = new Path();
 
     private final Rect mOutlineRect = new Rect();
+    private final Path mClipPath = new Path();
     private boolean mCustomOutline;
     private float mOutlineAlpha = -1f;
     private float mOutlineRadius;
@@ -69,13 +70,14 @@
     private float mBottomRoundness;
     private float mTopRoundness;
     private int mBackgroundTop;
-    protected int mCurrentSidePaddings;
 
     /**
      * {@code true} if the children views of the {@link ExpandableOutlineView} are translated when
      * it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself.
      */
     protected boolean mShouldTranslateContents;
+    private boolean mClipRoundedToClipTopAmount;
+    private float mDistanceToTopRoundness = -1;
 
     private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
         @Override
@@ -83,9 +85,9 @@
             if (!mCustomOutline && mCurrentTopRoundness == 0.0f
                     && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners) {
                 int translation = mShouldTranslateContents ? (int) getTranslation() : 0;
-                int left = Math.max(translation + mCurrentSidePaddings, mCurrentSidePaddings);
+                int left = Math.max(translation, 0);
                 int top = mClipTopAmount + mBackgroundTop;
-                int right = getWidth() - mCurrentSidePaddings + Math.min(translation, 0);
+                int right = getWidth() + Math.min(translation, 0);
                 int bottom = Math.max(getActualHeight() - mClipBottomAmount, top);
                 outline.setRect(left, top, right, bottom);
             } else {
@@ -115,9 +117,9 @@
         if (!mCustomOutline) {
             int translation = mShouldTranslateContents && !ignoreTranslation
                     ? (int) getTranslation() : 0;
-            left = Math.max(translation + mCurrentSidePaddings, mCurrentSidePaddings);
+            left = Math.max(translation, 0);
             top = mClipTopAmount + mBackgroundTop;
-            right = getWidth() - mCurrentSidePaddings + Math.min(translation, 0);
+            right = getWidth() + Math.min(translation, 0);
             bottom = Math.max(getActualHeight(), top);
             int intersectBottom = Math.max(getActualHeight() - mClipBottomAmount, top);
             if (bottom != intersectBottom) {
@@ -135,8 +137,6 @@
             top = mOutlineRect.top;
             right = mOutlineRect.right;
             bottom = mOutlineRect.bottom;
-            left = Math.max(mCurrentSidePaddings, left);
-            right = Math.min(getWidth() - mCurrentSidePaddings, right);
         }
         height = bottom - top;
         if (height == 0) {
@@ -162,15 +162,8 @@
         return roundedRectPath;
     }
 
-    protected Path getRoundedRectPath(int left, int top, int right, int bottom, float topRoundness,
-            float bottomRoundness) {
-        getRoundedRectPath(left, top, right, bottom, topRoundness, bottomRoundness,
-                mTmpPath);
-        return mTmpPath;
-    }
-
-    private void getRoundedRectPath(int left, int top, int right, int bottom, float topRoundness,
-            float bottomRoundness, Path outPath) {
+    public static void getRoundedRectPath(int left, int top, int right, int bottom,
+            float topRoundness, float bottomRoundness, Path outPath) {
         outPath.reset();
         int width = right - left;
         float topRoundnessX = topRoundness;
@@ -207,20 +200,50 @@
     @Override
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         canvas.save();
+        Path intersectPath = null;
+        if (mClipRoundedToClipTopAmount) {
+            int left = 0;
+            int top = (int) (mClipTopAmount - mDistanceToTopRoundness);
+            int right = getWidth();
+            int bottom = (int) Math.max(getActualHeight() - mClipBottomAmount,
+                    top + mOutlineRadius);
+            ExpandableOutlineView.getRoundedRectPath(left, top, right, bottom, mOutlineRadius,
+                    0.0f,
+                    mClipPath);
+            intersectPath = mClipPath;
+        }
+        boolean clipped = false;
         if (childNeedsClipping(child)) {
             Path clipPath = getCustomClipPath(child);
             if (clipPath == null) {
                 clipPath = getClipPath();
             }
             if (clipPath != null) {
+                if (intersectPath != null) {
+                    clipPath.op(intersectPath, Path.Op.INTERSECT);
+                }
                 canvas.clipPath(clipPath);
+                clipped = true;
             }
         }
+        if (!clipped && intersectPath != null) {
+            canvas.clipPath(intersectPath);
+        }
         boolean result = super.drawChild(canvas, child, drawingTime);
         canvas.restore();
         return result;
     }
 
+    @Override
+    public void setDistanceToTopRoundness(float distanceToTopRoundness) {
+        super.setDistanceToTopRoundness(distanceToTopRoundness);
+        if (distanceToTopRoundness != mDistanceToTopRoundness) {
+            mClipRoundedToClipTopAmount = distanceToTopRoundness >= 0;
+            mDistanceToTopRoundness = distanceToTopRoundness;
+            invalidate();
+        }
+    }
+
     protected boolean childNeedsClipping(View child) {
         return false;
     }
@@ -395,10 +418,4 @@
     public Path getCustomClipPath(View child) {
         return null;
     }
-
-    public void setCurrentSidePaddings(float currentSidePaddings) {
-        mCurrentSidePaddings = (int) currentSidePaddings;
-        invalidateOutline();
-        invalidate();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index f762513..eafa825 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -130,6 +130,14 @@
         }
     }
 
+    /**
+     * Set the distance to the top roundness, from where we should start clipping a value above
+     * or equal to 0 is the effective distance, and if a value below 0 is received, there should
+     * be no clipping.
+     */
+    public void setDistanceToTopRoundness(float distanceToTopRoundness) {
+    }
+
     public void setActualHeight(int actualHeight) {
         setActualHeight(actualHeight, true /* notifyListeners */);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 569e58d..43047ed6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -52,6 +52,8 @@
 import com.android.systemui.util.wakelock.SettableWakeLock;
 import com.android.systemui.util.wakelock.WakeLock;
 
+import java.text.NumberFormat;
+
 /**
  * Controls the indications and error messages shown on the Keyguard
  */
@@ -78,7 +80,7 @@
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     private String mRestingIndication;
-    private String mTransientIndication;
+    private CharSequence mTransientIndication;
     private int mTransientTextColor;
     private int mInitialTextColor;
     private boolean mVisible;
@@ -87,6 +89,7 @@
     private boolean mPowerCharged;
     private int mChargingSpeed;
     private int mChargingWattage;
+    private int mBatteryLevel;
     private String mMessageToShowOnScreenOn;
 
     private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -246,14 +249,14 @@
     /**
      * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
      */
-    public void showTransientIndication(String transientIndication) {
+    public void showTransientIndication(CharSequence transientIndication) {
         showTransientIndication(transientIndication, mInitialTextColor);
     }
 
     /**
      * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
      */
-    public void showTransientIndication(String transientIndication, int textColor) {
+    public void showTransientIndication(CharSequence transientIndication, int textColor) {
         mTransientIndication = transientIndication;
         mTransientTextColor = textColor;
         mHandler.removeMessages(MSG_HIDE_TRANSIENT);
@@ -285,14 +288,18 @@
             // Walk down a precedence-ordered list of what indication
             // should be shown based on user or device state
             if (mDozing) {
-                // If we're dozing, never show a persistent indication.
+                mTextView.setTextColor(Color.WHITE);
                 if (!TextUtils.isEmpty(mTransientIndication)) {
                     // When dozing we ignore any text color and use white instead, because
                     // colors can be hard to read in low brightness.
-                    mTextView.setTextColor(Color.WHITE);
                     mTextView.switchIndication(mTransientIndication);
+                } else if (mPowerPluggedIn) {
+                    String indication = computePowerIndication();
+                    mTextView.switchIndication(indication);
                 } else {
-                    mTextView.switchIndication(null);
+                    String percentage = NumberFormat.getPercentInstance()
+                            .format(mBatteryLevel / 100f);
+                    mTextView.switchIndication(percentage);
                 }
                 return;
             }
@@ -422,6 +429,7 @@
             mPowerCharged = status.isCharged();
             mChargingWattage = status.maxChargingWattage;
             mChargingSpeed = status.getChargingSpeed(mSlowThreshold, mFastThreshold);
+            mBatteryLevel = status.level;
             updateIndication();
             if (mDozing) {
                 if (!wasPluggedIn && mPowerPluggedIn) {
@@ -490,6 +498,12 @@
         }
 
         @Override
+        public void onTrustAgentErrorMessage(CharSequence message) {
+            int errorColor = Utils.getColorError(mContext);
+            showTransientIndication(message, errorColor);
+        }
+
+        @Override
         public void onScreenTurnedOn() {
             if (mMessageToShowOnScreenOn != null) {
                 int errorColor = Utils.getColorError(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 68cf51c..45b35d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -41,7 +41,6 @@
     private int mClipBottomAmount;
     private int mTintColor;
     private float[] mCornerRadii = new float[8];
-    private int mCurrentSidePaddings;
     private boolean mBottomIsRounded;
     private int mBackgroundTop;
     private boolean mBottomAmountClips = true;
@@ -68,8 +67,7 @@
             if (mBottomIsRounded && mBottomAmountClips) {
                 bottom -= mClipBottomAmount;
             }
-            drawable.setBounds(mCurrentSidePaddings, mBackgroundTop,
-                    getWidth() - mCurrentSidePaddings, bottom);
+            drawable.setBounds(0, mBackgroundTop, getWidth(), bottom);
             drawable.draw(canvas);
         }
     }
@@ -206,11 +204,6 @@
         }
     }
 
-    public void setCurrentSidePaddings(float currentSidePaddings) {
-        mCurrentSidePaddings = (int) currentSidePaddings;
-        invalidate();
-    }
-
     public void setBackgroundTop(int backgroundTop) {
         mBackgroundTop = backgroundTop;
         invalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 39c2131..c73e548 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -136,7 +136,6 @@
     private int mClipBottomAmount;
     private boolean mIsLowPriority;
     private boolean mIsContentExpandable;
-    private int mCustomViewSidePaddings;
 
 
     public NotificationContentView(Context context, AttributeSet attrs) {
@@ -150,8 +149,6 @@
                 R.dimen.min_notification_layout_height);
         mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin_end);
-        mCustomViewSidePaddings = getResources().getDimensionPixelSize(
-                R.dimen.notification_content_custom_view_side_padding);
     }
 
     public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
@@ -391,22 +388,6 @@
         mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child,
                 mContainingNotification);
         mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
-        updateMargins(child);
-    }
-
-    private void updateMargins(View child) {
-        if (child == null) {
-            return;
-        }
-        NotificationViewWrapper wrapper = getWrapperForView(child);
-        boolean isCustomView = wrapper instanceof NotificationCustomViewWrapper;
-        boolean needsMargins = isCustomView &&
-                child.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P;
-        int padding = needsMargins ? mCustomViewSidePaddings : 0;
-        MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
-        layoutParams.setMarginStart(padding);
-        layoutParams.setMarginEnd(padding);
-        child.setLayoutParams(layoutParams);
     }
 
     private NotificationViewWrapper getWrapperForView(View child) {
@@ -456,7 +437,6 @@
         mExpandedChild = child;
         mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
                 mContainingNotification);
-        updateMargins(child);
     }
 
     public void setHeadsUpChild(View child) {
@@ -490,7 +470,6 @@
         mHeadsUpChild = child;
         mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
                 mContainingNotification);
-        updateMargins(child);
     }
 
     public void setAmbientChild(View child) {
@@ -1510,19 +1489,19 @@
         return false;
     }
 
-    public boolean shouldClipToSidePaddings() {
-        boolean needsPaddings = shouldClipToSidePaddings(getVisibleType());
+    public boolean shouldClipToRounding() {
+        boolean needsPaddings = shouldClipToRounding(getVisibleType());
         if (mUserExpanding) {
-             needsPaddings |= shouldClipToSidePaddings(mTransformationStartVisibleType);
+             needsPaddings |= shouldClipToRounding(mTransformationStartVisibleType);
         }
         return needsPaddings;
     }
 
-    private boolean shouldClipToSidePaddings(int visibleType) {
+    private boolean shouldClipToRounding(int visibleType) {
         NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
         if (visibleWrapper == null) {
             return false;
         }
-        return visibleWrapper.shouldClipToSidePaddings();
+        return visibleWrapper.shouldClipToRounding();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index 87ad6f6b..441c184 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -229,10 +229,9 @@
                 }
             }
             try {
-                info.bindNotification(pmUser, iNotificationManager, pkg, new ArrayList(channels),
-                        row.getEntry().channel.getImportance(), sbn, onSettingsClick,
-                        onAppSettingsClick, onDoneClick, mCheckSaveListener,
-                        mNonBlockablePkgs);
+                info.bindNotification(pmUser, iNotificationManager, pkg, row.getEntry().channel,
+                        channels.size(), sbn, mCheckSaveListener, onSettingsClick,
+                        onAppSettingsClick, mNonBlockablePkgs);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
index 4301817..1127075 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
@@ -128,6 +128,7 @@
         mComparators.add(HeaderProcessor.forTextView(mRow,
                 com.android.internal.R.id.header_text));
         mDividers.add(com.android.internal.R.id.header_text_divider);
+        mDividers.add(com.android.internal.R.id.header_text_secondary_divider);
         mDividers.add(com.android.internal.R.id.time_divider);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 8d1bb5f..6279fdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -18,6 +18,10 @@
 
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -38,12 +42,12 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.Switch;
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.Utils;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 import java.lang.IllegalArgumentException;
@@ -57,25 +61,37 @@
     private static final String TAG = "InfoGuts";
 
     private INotificationManager mINotificationManager;
+    private PackageManager mPm;
+
     private String mPkg;
     private String mAppName;
     private int mAppUid;
-    private List<NotificationChannel> mNotificationChannels;
+    private int mNumNotificationChannels;
     private NotificationChannel mSingleNotificationChannel;
-    private boolean mIsSingleDefaultChannel;
-    private StatusBarNotification mSbn;
     private int mStartingUserImportance;
+    private int mChosenImportance;
+    private boolean mIsSingleDefaultChannel;
+    private boolean mNonblockable;
+    private StatusBarNotification mSbn;
+    private AnimatorSet mExpandAnimation;
 
-    private TextView mNumChannelsView;
-    private View mChannelDisabledView;
-    private TextView mSettingsLinkView;
-    private Switch mChannelEnabledSwitch;
     private CheckSaveListener mCheckSaveListener;
+    private OnSettingsClickListener mOnSettingsClickListener;
     private OnAppSettingsClickListener mAppSettingsClickListener;
-    private PackageManager mPm;
-
     private NotificationGuts mGutsContainer;
 
+    private OnClickListener mOnKeepShowing = v -> {
+        closeControls(v);
+    };
+
+    private OnClickListener mOnStopNotifications = v -> {
+        swapContent(false);
+    };
+
+    private OnClickListener mOnUndo = v -> {
+        swapContent(true);
+    };
+
     public NotificationInfo(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -98,141 +114,93 @@
     public void bindNotification(final PackageManager pm,
             final INotificationManager iNotificationManager,
             final String pkg,
-            final List<NotificationChannel> notificationChannels,
-            int startingUserImportance,
+            final NotificationChannel notificationChannel,
+            final int numChannels,
             final StatusBarNotification sbn,
-            OnSettingsClickListener onSettingsClick,
-            OnAppSettingsClickListener onAppSettingsClick,
-            OnClickListener onDoneClick,
-            CheckSaveListener checkSaveListener,
+            final CheckSaveListener checkSaveListener,
+            final OnSettingsClickListener onSettingsClick,
+            final OnAppSettingsClickListener onAppSettingsClick,
             final Set<String> nonBlockablePkgs)
             throws RemoteException {
         mINotificationManager = iNotificationManager;
         mPkg = pkg;
-        mNotificationChannels = notificationChannels;
-        mCheckSaveListener = checkSaveListener;
+        mNumNotificationChannels = numChannels;
         mSbn = sbn;
         mPm = pm;
         mAppSettingsClickListener = onAppSettingsClick;
-        mStartingUserImportance = startingUserImportance;
         mAppName = mPkg;
-        Drawable pkgicon = null;
-        CharSequence channelNameText = "";
-        ApplicationInfo info = null;
-        try {
-            info = pm.getApplicationInfo(mPkg,
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES
-                            | PackageManager.MATCH_DISABLED_COMPONENTS
-                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
-            if (info != null) {
-                mAppUid = sbn.getUid();
-                mAppName = String.valueOf(pm.getApplicationLabel(info));
-                pkgicon = pm.getApplicationIcon(info);
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            // app is gone, just show package name and generic icon
-            pkgicon = pm.getDefaultActivityIcon();
-        }
-        ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
+        mCheckSaveListener = checkSaveListener;
+        mOnSettingsClickListener = onSettingsClick;
+        mSingleNotificationChannel = notificationChannel;
+        mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
 
-        int numTotalChannels = iNotificationManager.getNumNotificationChannelsForPackage(
+        int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
                 pkg, mAppUid, false /* includeDeleted */);
-        if (mNotificationChannels.isEmpty()) {
+        if (mNumNotificationChannels == 0) {
             throw new IllegalArgumentException("bindNotification requires at least one channel");
         } else  {
-            if (mNotificationChannels.size() == 1) {
-                mSingleNotificationChannel = mNotificationChannels.get(0);
-                // Special behavior for the Default channel if no other channels have been defined.
-                mIsSingleDefaultChannel =
-                        (mSingleNotificationChannel.getId()
-                                .equals(NotificationChannel.DEFAULT_CHANNEL_ID) &&
-                        numTotalChannels <= 1);
-            } else {
-                mSingleNotificationChannel = null;
-                mIsSingleDefaultChannel = false;
-            }
+            // Special behavior for the Default channel if no other channels have been defined.
+            mIsSingleDefaultChannel = mNumNotificationChannels == 1
+                    && mSingleNotificationChannel.getId()
+                    .equals(NotificationChannel.DEFAULT_CHANNEL_ID)
+                    && numTotalChannels <= 1;
         }
 
-        boolean nonBlockable = false;
         try {
             final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
             if (Utils.isSystemPackage(getResources(), pm, pkgInfo)) {
-                final int numChannels = mNotificationChannels.size();
-                for (int i = 0; i < numChannels; i++) {
-                    final NotificationChannel notificationChannel = mNotificationChannels.get(i);
-                    // If any of the system channels is not blockable, the bundle is nonblockable
-                    if (!notificationChannel.isBlockableSystem()) {
-                        nonBlockable = true;
-                        break;
-                    }
+                if (mSingleNotificationChannel != null
+                        && !mSingleNotificationChannel.isBlockableSystem()) {
+                    mNonblockable = true;
                 }
             }
         } catch (PackageManager.NameNotFoundException e) {
             // unlikely.
         }
         if (nonBlockablePkgs != null) {
-            nonBlockable |= nonBlockablePkgs.contains(pkg);
+            mNonblockable |= nonBlockablePkgs.contains(pkg);
         }
+        mNonblockable |= (mNumNotificationChannels > 1);
 
-        String channelsDescText;
-        mNumChannelsView = findViewById(R.id.num_channels_desc);
-        if (nonBlockable) {
-            channelsDescText = mContext.getString(R.string.notification_unblockable_desc);
-        } else if (mIsSingleDefaultChannel) {
-            channelsDescText = mContext.getString(R.string.notification_default_channel_desc);
-        } else {
-            switch (mNotificationChannels.size()) {
-                case 1:
-                    channelsDescText = String.format(mContext.getResources().getQuantityString(
-                            R.plurals.notification_num_channels_desc, numTotalChannels),
-                            numTotalChannels);
-                    break;
-                case 2:
-                    channelsDescText = mContext.getString(
-                            R.string.notification_channels_list_desc_2,
-                            mNotificationChannels.get(0).getName(),
-                            mNotificationChannels.get(1).getName());
-                    break;
-                default:
-                    final int numOthers = mNotificationChannels.size() - 2;
-                    channelsDescText = String.format(
-                            mContext.getResources().getQuantityString(
-                                    R.plurals.notification_channels_list_desc_2_and_others,
-                                    numOthers),
-                            mNotificationChannels.get(0).getName(),
-                            mNotificationChannels.get(1).getName(),
-                            numOthers);
+        bindHeader();
+        bindPrompt();
+        bindButtons();
+    }
+
+    private void bindHeader() throws RemoteException {
+        // Package name
+        Drawable pkgicon = null;
+        ApplicationInfo info;
+        try {
+            info = mPm.getApplicationInfo(mPkg,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES
+                            | PackageManager.MATCH_DISABLED_COMPONENTS
+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+            if (info != null) {
+                mAppUid = mSbn.getUid();
+                mAppName = String.valueOf(mPm.getApplicationLabel(info));
+                pkgicon = mPm.getApplicationIcon(info);
             }
+        } catch (PackageManager.NameNotFoundException e) {
+            // app is gone, just show package name and generic icon
+            pkgicon = mPm.getDefaultActivityIcon();
         }
-        mNumChannelsView.setText(channelsDescText);
-
-        if (mSingleNotificationChannel == null) {
-            // Multiple channels don't use a channel name for the title.
-            channelNameText = mContext.getString(R.string.notification_num_channels,
-                    mNotificationChannels.size());
-        } else if (mIsSingleDefaultChannel || nonBlockable) {
-            // If this is the default channel or the app is unblockable,
-            // don't use our channel-specific text.
-            channelNameText = mContext.getString(R.string.notification_header_default_channel);
-        } else {
-            channelNameText = mSingleNotificationChannel.getName();
-        }
+        ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
         ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
-        ((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
 
         // Set group information if this channel has an associated group.
         CharSequence groupName = null;
         if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
             final NotificationChannelGroup notificationChannelGroup =
-                    iNotificationManager.getNotificationChannelGroupForPackage(
-                            mSingleNotificationChannel.getGroup(), pkg, mAppUid);
+                    mINotificationManager.getNotificationChannelGroupForPackage(
+                            mSingleNotificationChannel.getGroup(), mPkg, mAppUid);
             if (notificationChannelGroup != null) {
                 groupName = notificationChannelGroup.getName();
             }
         }
-        TextView groupNameView = ((TextView) findViewById(R.id.group_name));
-        TextView groupDividerView = ((TextView) findViewById(R.id.pkg_group_divider));
+        TextView groupNameView = findViewById(R.id.group_name);
+        TextView groupDividerView = findViewById(R.id.pkg_group_divider);
         if (groupName != null) {
             groupNameView.setText(groupName);
             groupNameView.setVisibility(View.VISIBLE);
@@ -242,53 +210,55 @@
             groupDividerView.setVisibility(View.GONE);
         }
 
-        bindButtons(nonBlockable);
-
-        // Top-level importance group
-        mChannelDisabledView = findViewById(R.id.channel_disabled);
-        updateSecondaryText();
-
         // Settings button.
-        final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
-        if (mAppUid >= 0 && onSettingsClick != null) {
+        final View settingsButton = findViewById(R.id.info);
+        if (mAppUid >= 0 && mOnSettingsClickListener != null) {
             settingsButton.setVisibility(View.VISIBLE);
             final int appUidF = mAppUid;
             settingsButton.setOnClickListener(
                     (View view) -> {
-                        onSettingsClick.onClick(view, mSingleNotificationChannel, appUidF);
+                        mOnSettingsClickListener.onClick(view,
+                                mNumNotificationChannels > 1 ? null : mSingleNotificationChannel,
+                                appUidF);
                     });
-            if (numTotalChannels <= 1 || nonBlockable) {
-                settingsButton.setText(R.string.notification_more_settings);
-            } else {
-                settingsButton.setText(R.string.notification_all_categories);
-            }
         } else {
             settingsButton.setVisibility(View.GONE);
         }
+    }
 
-        // Done button.
-        final TextView doneButton = (TextView) findViewById(R.id.done);
-        doneButton.setText(R.string.notification_done);
-        doneButton.setOnClickListener(onDoneClick);
+    private void bindPrompt() {
+        final TextView channelName = findViewById(R.id.channel_name);
+        final TextView blockPrompt = findViewById(R.id.block_prompt);
+        if (mNonblockable) {
+            if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
+                channelName.setVisibility(View.GONE);
+            } else {
+                channelName.setText(mSingleNotificationChannel.getName());
+            }
 
-        // Optional settings link
-        updateAppSettingsLink();
+            blockPrompt.setText(R.string.notification_unblockable_desc);
+        } else {
+            if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
+                channelName.setVisibility(View.GONE);
+                blockPrompt.setText(R.string.inline_keep_showing_app);
+            } else {
+                channelName.setText(mSingleNotificationChannel.getName());
+                blockPrompt.setText(R.string.inline_keep_showing);
+            }
+        }
     }
 
     private boolean hasImportanceChanged() {
-        return mSingleNotificationChannel != null &&
-                mChannelEnabledSwitch != null &&
-                mStartingUserImportance != getSelectedImportance();
+        return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
     }
 
     private void saveImportance() {
-        if (!hasImportanceChanged()) {
+        if (mNonblockable || !hasImportanceChanged()) {
             return;
         }
-        final int selectedImportance = getSelectedImportance();
         MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
-                selectedImportance - mStartingUserImportance);
-        mSingleNotificationChannel.setImportance(selectedImportance);
+                mChosenImportance - mStartingUserImportance);
+        mSingleNotificationChannel.setImportance(mChosenImportance);
         mSingleNotificationChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
         try {
             mINotificationManager.updateNotificationChannelForPackage(
@@ -298,30 +268,78 @@
         }
     }
 
-    private int getSelectedImportance() {
-        if (!mChannelEnabledSwitch.isChecked()) {
-            return IMPORTANCE_NONE;
+    private void bindButtons() {
+        View block =  findViewById(R.id.block);
+        block.setOnClickListener(mOnStopNotifications);
+        TextView keep = findViewById(R.id.keep);
+        keep.setOnClickListener(mOnKeepShowing);
+        findViewById(R.id.undo).setOnClickListener(mOnUndo);
+
+        if (mNonblockable) {
+            keep.setText(R.string.notification_done);
+            block.setVisibility(GONE);
+        }
+
+        // app settings link
+        TextView settingsLinkView = findViewById(R.id.app_settings);
+        Intent settingsIntent = getAppSettingsIntent(mPm, mPkg, mSingleNotificationChannel,
+                mSbn.getId(), mSbn.getTag());
+        if (settingsIntent != null
+                && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
+            settingsLinkView.setVisibility(View.VISIBLE);
+            settingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
+                    mSbn.getNotification().getSettingsText()));
+            settingsLinkView.setOnClickListener((View view) -> {
+                mAppSettingsClickListener.onClick(view, settingsIntent);
+            });
         } else {
-            return mStartingUserImportance;
+            settingsLinkView.setVisibility(View.GONE);
         }
     }
 
-    private void bindButtons(final boolean nonBlockable) {
-        // Enabled Switch
-        mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
-        mChannelEnabledSwitch.setChecked(
-                mStartingUserImportance != IMPORTANCE_NONE);
-        final boolean visible = !nonBlockable && mSingleNotificationChannel != null;
-        mChannelEnabledSwitch.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+    private void swapContent(boolean showPrompt) {
+        if (mExpandAnimation != null) {
+            mExpandAnimation.cancel();
+        }
 
-        // Callback when checked.
-        mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
-            if (mGutsContainer != null) {
-                mGutsContainer.resetFalsingCheck();
+        if (showPrompt) {
+            mChosenImportance = mStartingUserImportance;
+        } else {
+            mChosenImportance = IMPORTANCE_NONE;
+        }
+
+        View prompt = findViewById(R.id.prompt);
+        View confirmation = findViewById(R.id.confirmation);
+        ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
+                prompt.getAlpha(), showPrompt ? 1f : 0f);
+        promptAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
+        ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
+                confirmation.getAlpha(), showPrompt ? 0f : 1f);
+        confirmAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
+
+        prompt.setVisibility(showPrompt ? VISIBLE : GONE);
+        confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
+
+        mExpandAnimation = new AnimatorSet();
+        mExpandAnimation.playTogether(promptAnim, confirmAnim);
+        mExpandAnimation.setDuration(150);
+        mExpandAnimation.addListener(new AnimatorListenerAdapter() {
+            boolean cancelled = false;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                cancelled = true;
             }
-            updateSecondaryText();
-            updateAppSettingsLink();
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!cancelled) {
+                    prompt.setVisibility(showPrompt ? VISIBLE : GONE);
+                    confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
+                }
+            }
         });
+        mExpandAnimation.start();
     }
 
     @Override
@@ -339,35 +357,6 @@
         }
     }
 
-    private void updateSecondaryText() {
-        final boolean disabled = mSingleNotificationChannel != null &&
-                getSelectedImportance() == IMPORTANCE_NONE;
-        if (disabled) {
-            mChannelDisabledView.setVisibility(View.VISIBLE);
-            mNumChannelsView.setVisibility(View.GONE);
-        } else {
-            mChannelDisabledView.setVisibility(View.GONE);
-            mNumChannelsView.setVisibility(mIsSingleDefaultChannel ? View.INVISIBLE : View.VISIBLE);
-        }
-    }
-
-    private void updateAppSettingsLink() {
-        mSettingsLinkView = findViewById(R.id.app_settings);
-        Intent settingsIntent = getAppSettingsIntent(mPm, mPkg, mSingleNotificationChannel,
-                mSbn.getId(), mSbn.getTag());
-        if (settingsIntent != null && getSelectedImportance() != IMPORTANCE_NONE
-                && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
-            mSettingsLinkView.setVisibility(View.VISIBLE);
-            mSettingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
-                    mSbn.getNotification().getSettingsText()));
-            mSettingsLinkView.setOnClickListener((View view) -> {
-                mAppSettingsClickListener.onClick(view, settingsIntent);
-            });
-        } else {
-            mSettingsLinkView.setVisibility(View.GONE);
-        }
-    }
-
     private Intent getAppSettingsIntent(PackageManager pm, String packageName,
             NotificationChannel channel, int id, String tag) {
         Intent intent = new Intent(Intent.ACTION_MAIN)
@@ -390,6 +379,18 @@
         return intent;
     }
 
+    private void closeControls(View v) {
+        int[] parentLoc = new int[2];
+        int[] targetLoc = new int[2];
+        mGutsContainer.getLocationOnScreen(parentLoc);
+        v.getLocationOnScreen(targetLoc);
+        final int centerX = v.getWidth() / 2;
+        final int centerY = v.getHeight() / 2;
+        final int x = targetLoc[0] - parentLoc[0] + centerX;
+        final int y = targetLoc[1] - parentLoc[1] + centerY;
+        mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
+    }
+
     @Override
     public void setGutsParent(NotificationGuts guts) {
         mGutsContainer = guts;
@@ -397,7 +398,7 @@
 
     @Override
     public boolean willBeRemoved() {
-        return mChannelEnabledSwitch != null && !mChannelEnabledSwitch.isChecked();
+        return hasImportanceChanged();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index b2604fe..037eeb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -176,8 +176,6 @@
         final Resources res = mContext.getResources();
         mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
         mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
-        mSidePadding = res.getDimensionPixelSize(R.dimen.notification_lockscreen_side_paddings);
-        mIconPadding = res.getDimensionPixelSize(R.dimen.notification_menu_icon_padding);
         mMenuItems.clear();
         // Construct the menu items based on the notification
         if (mParent != null && mParent.getStatusBarNotification() != null) {
@@ -498,8 +496,8 @@
         final int count = mMenuContainer.getChildCount();
         for (int i = 0; i < count; i++) {
             final View v = mMenuContainer.getChildAt(i);
-            final float left = mSidePadding + i * mHorizSpaceForIcon;
-            final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1)) - mSidePadding;
+            final float left = i * mHorizSpaceForIcon;
+            final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1));
             v.setX(showOnLeft ? left : right);
         }
         mOnLeft = showOnLeft;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 66682e4..0d22095 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -38,7 +38,6 @@
     private final Paint mGreyPaint = new Paint();
     private boolean mIsLegacy;
     private int mLegacyColor;
-    private boolean mBeforeP;
 
     protected NotificationCustomViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
         super(ctx, view, row);
@@ -119,15 +118,7 @@
     }
 
     @Override
-    public boolean shouldClipToSidePaddings() {
-        // Before P we ensure that they are now drawing inside out content bounds since we inset
-        // the view. If they target P, then we don't have that guarantee and we need to be safe.
-        return !mBeforeP;
-    }
-
-    @Override
-    public void onContentUpdated(ExpandableNotificationRow row) {
-        super.onContentUpdated(row);
-        mBeforeP = row.getEntry().targetSdk < Build.VERSION_CODES.P;
+    public boolean shouldClipToRounding() {
+        return true;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index 060e6d6..d7c08cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -62,7 +62,7 @@
     }
 
     @Override
-    public boolean shouldClipToSidePaddings() {
+    public boolean shouldClipToRounding() {
         return true;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index e07112f..fd085d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -265,11 +265,6 @@
         updateActionOffset();
     }
 
-    @Override
-    public boolean shouldClipToSidePaddings() {
-        return mActionsContainer != null && mActionsContainer.getVisibility() != View.GONE;
-    }
-
     private void updateActionOffset() {
         if (mActionsContainer != null) {
             // We should never push the actions higher than they are in the headsup view.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 8a767bb..c71d604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -195,7 +195,7 @@
         return 0;
     }
 
-    public boolean shouldClipToSidePaddings() {
+    public boolean shouldClipToRounding() {
         return false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index a83e659..9b123cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -14,7 +14,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.graphics.drawable.Drawable;
 import android.view.View;
 
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
@@ -39,6 +38,7 @@
     private Integer mAlpha;
     private Float mDarkIntensity;
     private Integer mVisibility = -1;
+    private Boolean mDelayTouchFeedback;
     private KeyButtonDrawable mImageDrawable;
     private View mCurrentView;
     private boolean mVertical;
@@ -71,10 +71,10 @@
         if (mImageDrawable != null) {
             ((ButtonInterface) view).setImageDrawable(mImageDrawable);
         }
-
-        if (view instanceof  ButtonInterface) {
-            ((ButtonInterface) view).setVertical(mVertical);
+        if (mDelayTouchFeedback != null) {
+            ((ButtonInterface) view).setDelayTouchFeedback(mDelayTouchFeedback);
         }
+        ((ButtonInterface) view).setVertical(mVertical);
     }
 
     public int getId() {
@@ -89,6 +89,10 @@
         return mAlpha != null ? mAlpha : 1;
     }
 
+    public KeyButtonDrawable getImageDrawable() {
+        return mImageDrawable;
+    }
+
     public void setImageDrawable(KeyButtonDrawable drawable) {
         mImageDrawable = drawable;
         final int N = mViews.size();
@@ -130,6 +134,14 @@
         }
     }
 
+    public void setDelayTouchFeedback(boolean delay) {
+        mDelayTouchFeedback = delay;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            ((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
+        }
+    }
+
     public void setOnClickListener(View.OnClickListener clickListener) {
         mClickListener = clickListener;
         final int N = mViews.size();
@@ -162,6 +174,14 @@
         }
     }
 
+    public void setClickable(boolean clickable) {
+        abortCurrentGesture();
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setClickable(clickable);
+        }
+    }
+
     public ArrayList<View> getViews() {
         return mViews;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 01b3b44..ca66e98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -51,6 +51,7 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
@@ -166,6 +167,10 @@
     private String mLeftButtonStr;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mDozing;
+    private int mIndicationBottomMargin;
+    private int mIndicationBottomMarginAmbient;
+    private float mDarkAmount;
+    private int mBurnInXOffset;
 
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
@@ -235,6 +240,10 @@
         mEnterpriseDisclosure = findViewById(
                 R.id.keyguard_indication_enterprise_disclosure);
         mIndicationText = findViewById(R.id.keyguard_indication_text);
+        mIndicationBottomMargin = getResources().getDimensionPixelSize(
+                R.dimen.keyguard_indication_margin_bottom);
+        mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
+                R.dimen.keyguard_indication_margin_bottom_ambient);
         updateCameraVisibility();
         mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
         mUnlockMethodCache.addListener(this);
@@ -303,11 +312,13 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        int indicationBottomMargin = getResources().getDimensionPixelSize(
+        mIndicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
+        mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
+                R.dimen.keyguard_indication_margin_bottom_ambient);
         MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
-        if (mlp.bottomMargin != indicationBottomMargin) {
-            mlp.bottomMargin = indicationBottomMargin;
+        if (mlp.bottomMargin != mIndicationBottomMargin) {
+            mlp.bottomMargin = mIndicationBottomMargin;
             mIndicationArea.setLayoutParams(mlp);
         }
 
@@ -543,6 +554,22 @@
         }
     }
 
+    public void setDarkAmount(float darkAmount) {
+        if (darkAmount == mDarkAmount) {
+            return;
+        }
+        mDarkAmount = darkAmount;
+        // Let's randomize the bottom margin every time we wake up to avoid burn-in.
+        if (darkAmount == 0) {
+            mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
+                    R.dimen.keyguard_indication_margin_bottom_ambient)
+                    + (int) (Math.random() * mIndicationText.getTextSize());
+        }
+        mIndicationArea.setAlpha(MathUtils.lerp(1f, 0.7f, darkAmount));
+        mIndicationArea.setTranslationY(MathUtils.lerp(0,
+                mIndicationBottomMargin - mIndicationBottomMarginAmbient, darkAmount));
+    }
+
     private static boolean isSuccessfulLaunch(int result) {
         return result == ActivityManager.START_SUCCESS
                 || result == ActivityManager.START_DELIVERED_TO_TOP
@@ -687,11 +714,6 @@
         if (mRightAffordanceView.getVisibility() == View.VISIBLE) {
             startFinishDozeAnimationElement(mRightAffordanceView, delay);
         }
-        mIndicationArea.setAlpha(0f);
-        mIndicationArea.animate()
-                .alpha(1f)
-                .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
-                .setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
     }
 
     private void startFinishDozeAnimationElement(View element, long delay) {
@@ -815,6 +837,22 @@
         }
     }
 
+    public void dozeTimeTick() {
+        if (mDarkAmount == 1) {
+            // Move indication every minute to avoid burn-in
+            final int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient;
+            mIndicationArea.setTranslationY(dozeTranslation + (float) Math.random() * 5);
+        }
+    }
+
+    public void setBurnInXOffset(int burnInXOffset) {
+        if (mBurnInXOffset == burnInXOffset) {
+            return;
+        }
+        mBurnInXOffset = burnInXOffset;
+        mIndicationArea.setTranslationX(burnInXOffset);
+    }
+
     private class DefaultLeftButton implements IntentButton {
 
         private IconState mIconState = new IconState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index b71ebfd..699e8cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -131,6 +131,10 @@
             mRoot.setVisibility(View.VISIBLE);
             mKeyguardView.onResume();
             showPromptReason(mBouncerPromptReason);
+            final CharSequence customMessage = mCallback.consumeCustomMessage();
+            if (customMessage != null) {
+                mKeyguardView.showErrorMessage(customMessage);
+            }
             // We might still be collapsed and the view didn't have time to layout yet or still
             // be small, let's wait on the predraw to do the animation in that case.
             if (mKeyguardView.getHeight() != 0 && mKeyguardView.getHeight() != mStatusBarHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 34486db..264f574 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -250,7 +250,7 @@
                 }
                 break;
             case STATE_FACE_UNLOCK:
-                iconRes = R.drawable.ic_account_circle;
+                iconRes = R.drawable.ic_face_unlock;
                 break;
             case STATE_FINGERPRINT:
                 // If screen is off and device asleep, use the draw on animation so the first frame
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
index 7f4deb0..0f8d59b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
@@ -61,7 +61,7 @@
     public void setWorkModeEnabled(boolean enableWorkMode) {
         synchronized (mProfiles) {
             for (UserInfo ui : mProfiles) {
-                if (!mUserManager.trySetQuietModeEnabled(!enableWorkMode, UserHandle.of(ui.id))) {
+                if (!mUserManager.requestQuietModeEnabled(!enableWorkMode, UserHandle.of(ui.id))) {
                     StatusBarManager statusBarManager = (StatusBarManager) mContext
                             .getSystemService(android.app.Service.STATUS_BAR_SERVICE);
                     statusBarManager.collapsePanels();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 695168e..70ec45e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -24,6 +24,10 @@
 import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -39,6 +43,7 @@
 import android.database.ContentObserver;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
 import android.inputmethodservice.InputMethodService;
 import android.os.Binder;
 import android.os.Bundle;
@@ -70,17 +75,22 @@
 import com.android.internal.util.LatencyTracker;
 import com.android.systemui.Dependency;
 import com.android.systemui.OverviewProxyService;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 import com.android.systemui.statusbar.policy.KeyButtonView;
+import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 import java.io.FileDescriptor;
@@ -101,6 +111,8 @@
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
 
+    private static final int ROTATE_SUGGESTION_TIMEOUT_MS = 4000;
+
     protected NavigationBarView mNavigationBarView = null;
     protected AssistManager mAssistManager;
 
@@ -130,6 +142,15 @@
 
     public boolean mHomeBlockedThisTouch;
 
+    private int mLastRotationSuggestion;
+    private RotationLockController mRotationLockController;
+    private TaskStackListenerImpl mTaskStackListener;
+
+    private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false);
+    private Animator mRotateShowAnimator;
+    private Animator mRotateHideAnimator;
+
+
     // ----- Fragment Lifecycle Callbacks -----
 
     @Override
@@ -163,6 +184,12 @@
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+
+        mRotationLockController = Dependency.get(RotationLockController.class);
+
+        // Register the task stack listener
+        mTaskStackListener = new TaskStackListenerImpl();
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
     }
 
     @Override
@@ -178,6 +205,9 @@
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+
+        // Unregister the task stack listener
+        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
     }
 
     @Override
@@ -304,6 +334,92 @@
         }
     }
 
+    @Override
+    public void onRotationProposal(final int rotation) {
+        // This method will only be called if rotation is valid but will include proposals for the
+        // current system rotation
+        Handler h = getView().getHandler();
+        if (rotation == mWindowManager.getDefaultDisplay().getRotation()) {
+            // Use this as a signal to remove any current suggestions
+            h.removeCallbacks(mRemoveRotationProposal);
+            setRotateSuggestionButtonState(false);
+        } else {
+            mLastRotationSuggestion = rotation; // Remember rotation for click
+            setRotateSuggestionButtonState(true);
+            h.removeCallbacks(mRemoveRotationProposal); // Stop any pending removal
+            h.postDelayed(mRemoveRotationProposal,
+                    ROTATE_SUGGESTION_TIMEOUT_MS); // Schedule timeout
+        }
+    }
+
+    public void setRotateSuggestionButtonState(final boolean visible) {
+        setRotateSuggestionButtonState(visible, false);
+    }
+
+    public void setRotateSuggestionButtonState(final boolean visible, final boolean skipAnim) {
+        ButtonDispatcher rotBtn = mNavigationBarView.getRotateSuggestionButton();
+        boolean currentlyVisible = rotBtn.getVisibility() == View.VISIBLE;
+
+        // Rerun a show animation to indicate change but don't rerun a hide animation
+        if (!visible && !currentlyVisible) return;
+
+        View currentView = mNavigationBarView.getRotateSuggestionButton().getCurrentView();
+        if (currentView == null) return;
+
+        KeyButtonDrawable kbd = mNavigationBarView.getRotateSuggestionButton().getImageDrawable();
+        if (kbd == null) return;
+
+        AnimatedVectorDrawable animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0);
+        if (visible) { // Appear and change
+            rotBtn.setVisibility(View.VISIBLE);
+
+            if (skipAnim) {
+                currentView.setAlpha(1f);
+                return;
+            }
+
+            // Start a new animation if running
+            if (mRotateShowAnimator != null) mRotateShowAnimator.pause();
+            if (mRotateHideAnimator != null) mRotateHideAnimator.pause();
+
+            ObjectAnimator appearFade = ObjectAnimator.ofFloat(currentView, "alpha",
+                    0f, 1f);
+            appearFade.setDuration(100);
+            appearFade.setInterpolator(Interpolators.LINEAR);
+            mRotateShowAnimator = appearFade;
+            appearFade.start();
+
+            // Run the rotate icon's animation
+            animIcon.reset();
+            animIcon.start();
+        } else { // Hide
+
+            if (skipAnim) {
+                rotBtn.setVisibility(View.INVISIBLE);
+                return;
+            }
+
+            // Don't start any new hide animations if one is running
+            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
+            // Pause any active show animations but don't reset the AVD to avoid jumps
+            if (mRotateShowAnimator != null) mRotateShowAnimator.pause();
+
+            ObjectAnimator fadeOut = ObjectAnimator.ofFloat(currentView, "alpha",
+                    0f);
+            fadeOut.setDuration(100);
+            fadeOut.setInterpolator(Interpolators.LINEAR);
+            fadeOut.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    rotBtn.setVisibility(View.INVISIBLE);
+                }
+            });
+
+            mRotateHideAnimator = fadeOut;
+            fadeOut.start();
+        }
+    }
+
     // Injected from StatusBar at creation.
     public void setCurrentSysuiVisibility(int systemUiVisibility) {
         mSystemUiVisibility = systemUiVisibility;
@@ -406,6 +522,9 @@
         accessibilityButton.setOnClickListener(this::onAccessibilityClick);
         accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
         updateAccessibilityServicesState(mAccessibilityManager);
+
+        ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton();
+        rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick);
     }
 
     private boolean onHomeTouch(View v, MotionEvent event) {
@@ -598,6 +717,10 @@
         mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
     }
 
+    private void onRotateSuggestionClick(View v) {
+        mRotationLockController.setRotationLockedAtAngle(true, mLastRotationSuggestion);
+    }
+
     // ----- Methods that StatusBar talks to (should be minimized) -----
 
     public void setLightBarController(LightBarController lightBarController) {
@@ -646,6 +769,13 @@
     private final Stub mRotationWatcher = new Stub() {
         @Override
         public void onRotationChanged(int rotation) throws RemoteException {
+            // If the screen rotation changes while locked, update lock rotation to flow with
+            // new screen rotation and hide any showing suggestions.
+            if (mRotationLockController.isRotationLocked()) {
+                mRotationLockController.setRotationLockedAtAngle(true, rotation);
+                setRotateSuggestionButtonState(false, true);
+            }
+
             // We need this to be scheduled as early as possible to beat the redrawing of
             // window in response to the orientation change.
             Handler h = getView().getHandler();
@@ -671,6 +801,31 @@
         }
     };
 
+    class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
+        // Invalidate any rotation suggestion on task change or activity orientation change
+        // Note: all callbacks happen on main thread
+
+        @Override
+        public void onTaskStackChanged() {
+            setRotateSuggestionButtonState(false);
+        }
+
+        @Override
+        public void onTaskRemoved(int taskId) {
+            setRotateSuggestionButtonState(false);
+        }
+
+        @Override
+        public void onTaskMovedToFront(int taskId) {
+            setRotateSuggestionButtonState(false);
+        }
+
+        @Override
+        public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
+            setRotateSuggestionButtonState(false);
+        }
+    }
+
     public static View create(Context context, FragmentListener listener) {
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 6f636aa..4faa84a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -19,15 +19,14 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.util.Log;
-import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-import android.view.ViewConfiguration;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
@@ -37,6 +36,7 @@
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
+import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.tuner.TunerService;
 
@@ -72,6 +72,7 @@
     private NavigationBarView mNavigationBarView;
     private boolean mIsVertical;
 
+    private final QuickScrubController mQuickScrubController;
     private final int mScrollTouchSlop;
     private final Matrix mTransformGlobalMatrix = new Matrix();
     private final Matrix mTransformLocalMatrix = new Matrix();
@@ -89,6 +90,7 @@
         mContext = context;
         Resources r = context.getResources();
         mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
+        mQuickScrubController = new QuickScrubController(context);
         Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
     }
 
@@ -101,10 +103,12 @@
         mRecentsComponent = recentsComponent;
         mDivider = divider;
         mNavigationBarView = navigationBarView;
+        mQuickScrubController.setComponents(mNavigationBarView);
     }
 
     public void setBarState(boolean isVertical, boolean isRTL) {
         mIsVertical = isVertical;
+        mQuickScrubController.setBarState(isVertical, isRTL);
     }
 
     private boolean proxyMotionEvents(MotionEvent event) {
@@ -126,7 +130,6 @@
 
     public boolean onInterceptTouchEvent(MotionEvent event) {
         int action = event.getAction();
-        boolean result = false;
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 mTouchDownX = (int) event.getX();
@@ -137,24 +140,26 @@
                 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
                 break;
             }
-            case MotionEvent.ACTION_MOVE: {
-                int x = (int) event.getX();
-                int y = (int) event.getY();
-                int xDiff = Math.abs(x - mTouchDownX);
-                int yDiff = Math.abs(y - mTouchDownY);
-                boolean exceededTouchSlop = xDiff > mScrollTouchSlop && xDiff > yDiff
-                        || yDiff > mScrollTouchSlop && yDiff > xDiff;
-                if (exceededTouchSlop) {
-                    result = true;
-                }
-                break;
-            }
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                break;
         }
-        proxyMotionEvents(event);
-        return result || (mDockWindowEnabled && interceptDockWindowEvent(event));
+        if (!mQuickScrubController.onInterceptTouchEvent(event)) {
+            proxyMotionEvents(event);
+            return false;
+        }
+        return (mDockWindowEnabled && interceptDockWindowEvent(event));
+    }
+
+    public void onDraw(Canvas canvas) {
+        if (mOverviewEventSender.getProxy() != null) {
+            mQuickScrubController.onDraw(canvas);
+        }
+    }
+
+    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        mQuickScrubController.onLayout(changed, left, top, right, bottom);
+    }
+
+    public void onDarkIntensityChange(float intensity) {
+        mQuickScrubController.onDarkIntensityChange(intensity);
     }
 
     private boolean interceptDockWindowEvent(MotionEvent event) {
@@ -294,7 +299,7 @@
     }
 
     public boolean onTouchEvent(MotionEvent event) {
-        boolean result = proxyMotionEvents(event);
+        boolean result = mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event);
         if (mDockWindowEnabled) {
             result |= handleDockWindowEvent(event);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 4e79314b..b8b309b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -63,6 +63,7 @@
     public static final String RECENT = "recent";
     public static final String NAVSPACE = "space";
     public static final String CLIPBOARD = "clipboard";
+    public static final String ROTATE = "rotate";
     public static final String KEY = "key";
     public static final String LEFT = "left";
     public static final String RIGHT = "right";
@@ -311,7 +312,7 @@
         View v = null;
         String button = extractButton(buttonSpec);
         if (LEFT.equals(button)) {
-            String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, NAVSPACE);
+            String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, ROTATE);
             button = extractButton(s);
         } else if (RIGHT.equals(button)) {
             String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME);
@@ -334,6 +335,8 @@
             v = inflater.inflate(R.layout.nav_key_space, parent, false);
         } else if (CLIPBOARD.equals(button)) {
             v = inflater.inflate(R.layout.clipboard, parent, false);
+        } else if (ROTATE.equals(button)) {
+            v = inflater.inflate(R.layout.rotate_suggestion, parent, false);
         } else if (button.startsWith(KEY)) {
             String uri = extractImage(button);
             int code = extractKeycode(button);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index bd6421c..b113675 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -138,6 +138,7 @@
         if (mAutoDim) {
             applyLightsOut(false, true);
         }
+        mView.onDarkIntensityChange(darkIntensity);
     }
 
     private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 392581d..059ce92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -26,11 +26,13 @@
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
+import android.support.annotation.ColorInt;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -56,6 +58,7 @@
 import com.android.systemui.plugins.statusbar.phone.NavGesture;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
 import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.policy.TintedKeyButtonDrawable;
 import com.android.systemui.statusbar.policy.DeadZone;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 
@@ -94,6 +97,7 @@
     private KeyButtonDrawable mImeIcon;
     private KeyButtonDrawable mMenuIcon;
     private KeyButtonDrawable mAccessibilityIcon;
+    private KeyButtonDrawable mRotateSuggestionIcon;
 
     private GestureHelper mGestureHelper;
     private DeadZone mDeadZone;
@@ -229,6 +233,9 @@
         mButtonDispatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
         mButtonDispatchers.put(R.id.accessibility_button,
                 new ButtonDispatcher(R.id.accessibility_button));
+        mButtonDispatchers.put(R.id.rotate_suggestion,
+                new ButtonDispatcher(R.id.rotate_suggestion));
+
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
     }
 
@@ -305,6 +312,10 @@
         return mButtonDispatchers.get(R.id.accessibility_button);
     }
 
+    public ButtonDispatcher getRotateSuggestionButton() {
+        return mButtonDispatchers.get(R.id.rotate_suggestion);
+    }
+
     public SparseArray<ButtonDispatcher> getButtonDispatchers() {
         return mButtonDispatchers;
     }
@@ -349,6 +360,11 @@
             mImeIcon = getDrawable(darkContext, lightContext,
                     R.drawable.ic_ime_switcher_default, R.drawable.ic_ime_switcher_default);
 
+            int lightColor = Utils.getColorAttr(lightContext, R.attr.singleToneColor);
+            int darkColor = Utils.getColorAttr(darkContext, R.attr.singleToneColor);
+            mRotateSuggestionIcon = getDrawable(ctx, R.drawable.ic_sysbar_rotate_button,
+                    lightColor, darkColor);
+
             if (ALTERNATE_CAR_MODE_UI) {
                 updateCarModeIcons(ctx);
             }
@@ -366,6 +382,11 @@
                 darkContext.getDrawable(darkIcon));
     }
 
+    private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon,
+            @ColorInt int lightColor, @ColorInt int darkColor) {
+        return TintedKeyButtonDrawable.create(ctx.getDrawable(icon), lightColor, darkColor);
+    }
+
     @Override
     public void setLayoutDirection(int layoutDirection) {
         // Reload all the icons
@@ -439,6 +460,8 @@
         setAccessibilityButtonState(mShowAccessibilityButton, mLongClickableAccessibilityButton);
         getAccessibilityButton().setImageDrawable(mAccessibilityIcon);
 
+        getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
+
         setDisabledFlags(mDisabledFlags, true);
 
         mBarTransitions.reapplyDarkIntensity();
@@ -603,6 +626,24 @@
         updateRotatedViews();
     }
 
+    public void onDarkIntensityChange(float intensity) {
+        if (mGestureHelper != null) {
+            mGestureHelper.onDarkIntensityChange(intensity);
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        mGestureHelper.onDraw(canvas);
+        super.onDraw(canvas);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        mGestureHelper.onLayout(changed, left, top, right, bottom);
+    }
+
     private void updateRotatedViews() {
         mRotatedViews[Surface.ROTATION_0] =
                 mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index f0bd1f9..0cc7f5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -309,7 +309,7 @@
         mIndicationBottomPadding = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_bottom_padding);
         mQsNotificationTopPadding = getResources().getDimensionPixelSize(
-                R.dimen.qs_notification_keyguard_padding);
+                R.dimen.qs_notification_padding);
     }
 
     public void updateResources() {
@@ -451,7 +451,8 @@
         boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
         int stackScrollerPadding;
         if (mStatusBarState != StatusBarState.KEYGUARD) {
-            stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight;
+            stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight
+            +  mQsNotificationTopPadding;
             mTopPaddingAdjustment = 0;
         } else {
             mClockPositionAlgorithm.setup(
@@ -477,6 +478,7 @@
         }
         mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
         mNotificationStackScroller.setDarkShelfOffsetX(mClockPositionResult.clockX);
+        mKeyguardBottomArea.setBurnInXOffset(mClockPositionResult.clockX);
         requestScrollerTopPaddingUpdate(animate);
     }
 
@@ -1381,7 +1383,7 @@
                     mNotificationStackScroller.getIntrinsicPadding(),
                     mQsMaxExpansionHeight + mQsNotificationTopPadding);
         } else {
-            return mQsExpansionHeight;
+            return mQsExpansionHeight + mQsNotificationTopPadding;
         }
     }
 
@@ -2607,7 +2609,8 @@
 
     private void setDarkAmount(float amount) {
         mDarkAmount = amount;
-        mKeyguardStatusView.setDark(mDarkAmount);
+        mKeyguardStatusView.setDarkAmount(mDarkAmount);
+        mKeyguardBottomArea.setDarkAmount(mDarkAmount);
         positionClockAndNotifications();
     }
 
@@ -2629,8 +2632,9 @@
         }
     }
 
-    public void refreshTime() {
+    public void dozeTimeTick() {
         mKeyguardStatusView.refreshTime();
+        mKeyguardBottomArea.dozeTimeTick();
         if (mDarkAmount > 0) {
             positionClockAndNotifications();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
new file mode 100644
index 0000000..9f8a7ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Display;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.support.annotation.DimenRes;
+import com.android.systemui.Dependency;
+import com.android.systemui.OverviewProxyService;
+import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
+import com.android.systemui.shared.recents.IOverviewProxy;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+
+/**
+ * Class to detect gestures on the navigation bar and implement quick scrub and switch.
+ */
+public class QuickScrubController extends GestureDetector.SimpleOnGestureListener implements
+        GestureHelper {
+
+    private static final String TAG = "QuickScrubController";
+    private static final int QUICK_SWITCH_FLING_VELOCITY = 0;
+    private static final int ANIM_DURATION_MS = 200;
+    private static final long LONG_PRESS_DELAY_MS = 150;
+
+    /**
+     * For quick step, set a damping value to allow the button to stick closer its origin position
+     * when dragging before quick scrub is active.
+     */
+    private static final int SWITCH_STICKINESS = 4;
+
+    private NavigationBarView mNavigationBarView;
+    private GestureDetector mGestureDetector;
+
+    private boolean mDraggingActive;
+    private boolean mQuickScrubActive;
+    private float mDownOffset;
+    private float mTranslation;
+    private int mTouchDownX;
+    private int mTouchDownY;
+    private boolean mDragPositive;
+    private boolean mIsVertical;
+    private boolean mIsRTL;
+    private float mMaxTrackPaintAlpha;
+
+    private final Handler mHandler = new Handler();
+    private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
+    private final Rect mTrackRect = new Rect();
+    private final Rect mHomeButtonRect = new Rect();
+    private final Paint mTrackPaint = new Paint();
+    private final int mScrollTouchSlop;
+    private final OverviewProxyService mOverviewEventSender;
+    private final Display mDisplay;
+    private final int mTrackThickness;
+    private final int mTrackPadding;
+    private final ValueAnimator mTrackAnimator;
+    private final ValueAnimator mButtonAnimator;
+    private final AnimatorSet mQuickScrubEndAnimator;
+    private final Context mContext;
+
+    private final AnimatorUpdateListener mTrackAnimatorListener = valueAnimator -> {
+        mTrackPaint.setAlpha(Math.round((float) valueAnimator.getAnimatedValue() * 255));
+        mNavigationBarView.invalidate();
+    };
+
+    private final AnimatorUpdateListener mButtonTranslationListener = animator -> {
+        int pos = (int) animator.getAnimatedValue();
+        if (!mQuickScrubActive) {
+            pos = mDragPositive ? Math.min((int) mTranslation, pos) : Math.max((int) mTranslation, pos);
+        }
+        final View homeView = mNavigationBarView.getHomeButton().getCurrentView();
+        if (mIsVertical) {
+            homeView.setTranslationY(pos);
+        } else {
+            homeView.setTranslationX(pos);
+        }
+    };
+
+    private AnimatorListenerAdapter mQuickScrubEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mNavigationBarView.getHomeButton().setClickable(true);
+            mQuickScrubActive = false;
+            mTranslation = 0;
+        }
+    };
+
+    private Runnable mLongPressRunnable = this::startQuickScrub;
+
+    private final GestureDetector.SimpleOnGestureListener mGestureListener =
+        new GestureDetector.SimpleOnGestureListener() {
+            @Override
+            public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
+                if (mQuickScrubActive) {
+                    return false;
+                }
+                float velocityX = mIsRTL ? -velX : velX;
+                float absVelY = Math.abs(velY);
+                final boolean isValidFling = velocityX > QUICK_SWITCH_FLING_VELOCITY &&
+                        mIsVertical ? (absVelY > velocityX) : (velocityX > absVelY);
+                if (isValidFling) {
+                    mDraggingActive = false;
+                    mButtonAnimator.setIntValues((int) mTranslation, 0);
+                    mButtonAnimator.start();
+                    mHandler.removeCallbacks(mLongPressRunnable);
+                    try {
+                        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+                        overviewProxy.onQuickSwitch();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Failed to send start of quick switch.", e);
+                    }
+                }
+                return true;
+            }
+        };
+
+    public QuickScrubController(Context context) {
+        mContext = context;
+        mScrollTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mDisplay = ((WindowManager) context.getSystemService(
+                Context.WINDOW_SERVICE)).getDefaultDisplay();
+        mOverviewEventSender = Dependency.get(OverviewProxyService.class);
+        mGestureDetector = new GestureDetector(mContext, mGestureListener);
+        mTrackThickness = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_thickness);
+        mTrackPadding = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_edge_padding);
+
+        mTrackAnimator = ObjectAnimator.ofFloat();
+        mTrackAnimator.addUpdateListener(mTrackAnimatorListener);
+        mButtonAnimator = ObjectAnimator.ofInt();
+        mButtonAnimator.addUpdateListener(mButtonTranslationListener);
+        mQuickScrubEndAnimator = new AnimatorSet();
+        mQuickScrubEndAnimator.playTogether(mTrackAnimator, mButtonAnimator);
+        mQuickScrubEndAnimator.setDuration(ANIM_DURATION_MS);
+        mQuickScrubEndAnimator.addListener(mQuickScrubEndListener);
+        mQuickScrubEndAnimator.setInterpolator(mQuickScrubEndInterpolator);
+    }
+
+    public void setComponents(NavigationBarView navigationBarView) {
+        mNavigationBarView = navigationBarView;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+        final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
+        if (overviewProxy == null) {
+            homeButton.setDelayTouchFeedback(false);
+            return false;
+        }
+        mGestureDetector.onTouchEvent(event);
+        int action = event.getAction();
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN: {
+                int x = (int) event.getX();
+                int y = (int) event.getY();
+                if (mHomeButtonRect.contains(x, y)) {
+                    mTouchDownX = x;
+                    mTouchDownY = y;
+                    homeButton.setDelayTouchFeedback(true);
+                    mHandler.postDelayed(mLongPressRunnable, LONG_PRESS_DELAY_MS);
+                } else {
+                    mTouchDownX = mTouchDownY = -1;
+                }
+                break;
+            }
+            case MotionEvent.ACTION_MOVE: {
+                if (mTouchDownX != -1) {
+                    int x = (int) event.getX();
+                    int y = (int) event.getY();
+                    int xDiff = Math.abs(x - mTouchDownX);
+                    int yDiff = Math.abs(y - mTouchDownY);
+                    boolean exceededTouchSlop;
+                    int pos, touchDown, offset, trackSize;
+                    if (mIsVertical) {
+                        exceededTouchSlop = yDiff > mScrollTouchSlop && yDiff > xDiff;
+                        pos = y;
+                        touchDown = mTouchDownY;
+                        offset = pos - mTrackRect.top;
+                        trackSize = mTrackRect.height();
+                    } else {
+                        exceededTouchSlop = xDiff > mScrollTouchSlop && xDiff > yDiff;
+                        pos = x;
+                        touchDown = mTouchDownX;
+                        offset = pos - mTrackRect.left;
+                        trackSize = mTrackRect.width();
+                    }
+                    if (!mDragPositive) {
+                        offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
+                    }
+
+                    // Control the button movement
+                    if (!mDraggingActive && exceededTouchSlop) {
+                        boolean allowDrag = !mDragPositive
+                                ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
+                        if (allowDrag) {
+                            mDownOffset = offset;
+                            homeButton.setClickable(false);
+                            mDraggingActive = true;
+                        }
+                    }
+                    if (mDraggingActive && (mDragPositive && offset >= 0
+                            || !mDragPositive && offset <= 0)) {
+                        float scrubFraction =
+                                Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
+                        mTranslation = !mDragPositive
+                            ? Utilities.clamp(offset - mDownOffset, -trackSize, 0)
+                            : Utilities.clamp(offset - mDownOffset, 0, trackSize);
+                        if (mQuickScrubActive) {
+                            try {
+                                overviewProxy.onQuickScrubProgress(scrubFraction);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "Failed to send progress of quick scrub.", e);
+                            }
+                        } else {
+                            mTranslation /= SWITCH_STICKINESS;
+                        }
+                        if (mIsVertical) {
+                            homeButton.getCurrentView().setTranslationY(mTranslation);
+                        } else {
+                            homeButton.getCurrentView().setTranslationX(mTranslation);
+                        }
+                    }
+                }
+                break;
+            }
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                endQuickScrub();
+                break;
+        }
+        return mDraggingActive || mQuickScrubActive;
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        canvas.drawRect(mTrackRect, mTrackPaint);
+    }
+
+    @Override
+    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final int width = right - left;
+        final int height = bottom - top;
+        final int x1, x2, y1, y2;
+        if (mIsVertical) {
+            x1 = (width - mTrackThickness) / 2;
+            x2 = x1 + mTrackThickness;
+            y1 = mDragPositive ? height / 2 : mTrackPadding;
+            y2 = y1 + height / 2 - mTrackPadding;
+        } else {
+            y1 = (height - mTrackThickness) / 2;
+            y2 = y1 + mTrackThickness;
+            x1 = mDragPositive ? width / 2 : mTrackPadding;
+            x2 = x1 + width / 2 - mTrackPadding;
+        }
+        mTrackRect.set(x1, y1, x2, y2);
+
+        // Get the touch rect of the home button location
+        View homeView = mNavigationBarView.getHomeButton().getCurrentView();
+        int[] globalHomePos = homeView.getLocationOnScreen();
+        int[] globalNavBarPos = mNavigationBarView.getLocationOnScreen();
+        int homeX = globalHomePos[0] - globalNavBarPos[0];
+        int homeY = globalHomePos[1] - globalNavBarPos[1];
+        mHomeButtonRect.set(homeX, homeY, homeX + homeView.getMeasuredWidth(),
+                homeY + homeView.getMeasuredHeight());
+    }
+
+    @Override
+    public void onDarkIntensityChange(float intensity) {
+        if (intensity == 0) {
+            mTrackPaint.setColor(mContext.getColor(R.color.quick_step_track_background_light));
+        } else if (intensity == 1) {
+            mTrackPaint.setColor(mContext.getColor(R.color.quick_step_track_background_dark));
+        }
+        mMaxTrackPaintAlpha = mTrackPaint.getAlpha() * 1f / 255;
+        mTrackPaint.setAlpha(0);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_UP) {
+            endQuickScrub();
+        }
+        return false;
+    }
+
+    @Override
+    public void setBarState(boolean isVertical, boolean isRTL) {
+        mIsVertical = isVertical;
+        mIsRTL = isRTL;
+        try {
+            int navbarPos = WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
+            mDragPositive = navbarPos == NAV_BAR_LEFT || navbarPos == NAV_BAR_BOTTOM;
+            if (isRTL) {
+                mDragPositive = !mDragPositive;
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to get nav bar position.", e);
+        }
+    }
+
+    private void startQuickScrub() {
+        if (!mQuickScrubActive) {
+            mQuickScrubActive = true;
+            mTrackAnimator.setFloatValues(0, mMaxTrackPaintAlpha);
+            mTrackAnimator.start();
+            try {
+                mOverviewEventSender.getProxy().onQuickScrubStart();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to send start of quick scrub.", e);
+            }
+        }
+    }
+
+    private void endQuickScrub() {
+        mHandler.removeCallbacks(mLongPressRunnable);
+        if (mDraggingActive || mQuickScrubActive) {
+            mButtonAnimator.setIntValues((int) mTranslation, 0);
+            mTrackAnimator.setFloatValues(mTrackPaint.getAlpha() * 1f / 255, 0);
+            mQuickScrubEndAnimator.start();
+            try {
+                mOverviewEventSender.getProxy().onQuickScrubEnd();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to send end of quick scrub.", e);
+            }
+        }
+        mDraggingActive = false;
+    }
+
+    private int getDimensionPixelSize(Context context, @DimenRes int resId) {
+        return context.getResources().getDimensionPixelSize(resId);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 2da1e4d..af65a86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1596,7 +1596,7 @@
 
         final boolean hasArtwork = artworkDrawable != null;
 
-        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
+        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && !mDozing
                 && (mState != StatusBarState.SHADE || allowWhenShade)
                 && mFingerprintUnlockController.getMode()
                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
@@ -1657,15 +1657,16 @@
                 }
             }
         } else {
-            // need to hide the album art, either because we are unlocked or because
-            // the metadata isn't there to support it
+            // need to hide the album art, either because we are unlocked, on AOD
+            // or because the metadata isn't there to support it
             if (mBackdrop.getVisibility() != View.GONE) {
                 if (DEBUG_MEDIA) {
                     Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
                 }
+                boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange();
                 if (mFingerprintUnlockController.getMode()
                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
-                        || hideBecauseOccluded) {
+                        || hideBecauseOccluded || cannotAnimateDoze) {
 
                     // We are unlocking directly - no animation!
                     mBackdrop.setVisibility(View.GONE);
@@ -4644,7 +4645,7 @@
 
         @Override
         public void dozeTimeTick() {
-            mNotificationPanel.refreshTime();
+            mNotificationPanel.dozeTimeTick();
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 8504d8e..c667309 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -175,13 +175,18 @@
 
     public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
             boolean afterKeyguardGone) {
+        dismissWithAction(r, cancelAction, afterKeyguardGone, null /* message */);
+    }
+
+    public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
+            boolean afterKeyguardGone, String message) {
         if (mShowing) {
             cancelPendingWakeupAction();
             // If we're dozing, this needs to be delayed until after we wake up - unless we're
             // wake-and-unlocking, because there dozing will last until the end of the transition.
             if (mDozing && !isWakeAndUnlocking()) {
                 mPendingWakeupAction = new DismissWithActionRequest(
-                        r, cancelAction, afterKeyguardGone);
+                        r, cancelAction, afterKeyguardGone, message);
                 return;
             }
 
@@ -632,7 +637,7 @@
         if (request != null) {
             if (mShowing) {
                 dismissWithAction(request.dismissAction, request.cancelAction,
-                        request.afterKeyguardGone);
+                        request.afterKeyguardGone, request.message);
             } else if (request.dismissAction != null) {
                 request.dismissAction.onDismiss();
             }
@@ -651,12 +656,14 @@
         final OnDismissAction dismissAction;
         final Runnable cancelAction;
         final boolean afterKeyguardGone;
+        final String message;
 
         DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction,
-                boolean afterKeyguardGone) {
+                boolean afterKeyguardGone, String message) {
             this.dismissAction = dismissAction;
             this.cancelAction = cancelAction;
             this.afterKeyguardGone = afterKeyguardGone;
+            this.message = message;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index 21a96e2..cce9d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -39,7 +39,7 @@
         }
     }
 
-    private KeyButtonDrawable(Drawable[] drawables) {
+    protected KeyButtonDrawable(Drawable[] drawables) {
         super(drawables);
         for (int i = 0; i < drawables.length; i++) {
             setLayerGravity(i, Gravity.CENTER);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index cc7943b..a2bec98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -26,9 +26,11 @@
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
 import android.view.DisplayListCanvas;
 import android.view.RenderNodeAnimator;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.animation.Interpolator;
 
 import com.android.systemui.Interpolators;
@@ -56,14 +58,17 @@
     private float mGlowAlpha = 0f;
     private float mGlowScale = 1f;
     private boolean mPressed;
+    private boolean mVisible;
     private boolean mDrawingHardwareGlow;
     private int mMaxWidth;
     private boolean mLastDark;
     private boolean mDark;
+    private boolean mDelayTouchFeedback;
 
     private final Interpolator mInterpolator = new LogInterpolator();
     private boolean mSupportHardware;
     private final View mTargetView;
+    private final Handler mHandler = new Handler();
 
     private final HashSet<Animator> mRunningAnimations = new HashSet<>();
     private final ArrayList<Animator> mTmpArray = new ArrayList<>();
@@ -77,6 +82,10 @@
         mDark = darkIntensity >= 0.5f;
     }
 
+    public void setDelayTouchFeedback(boolean delay) {
+        mDelayTouchFeedback = delay;
+    }
+
     private Paint getRipplePaint() {
         if (mRipplePaint == null) {
             mRipplePaint = new Paint();
@@ -211,7 +220,16 @@
         }
     }
 
+    /**
+     * Abort the ripple while it is delayed and before shown used only when setShouldDelayStartTouch
+     * is enabled.
+     */
+    public void abortDelayedRipple() {
+        mHandler.removeCallbacksAndMessages(null);
+    }
+
     private void cancelAnimations() {
+        mVisible = false;
         mTmpArray.addAll(mRunningAnimations);
         int size = mTmpArray.size();
         for (int i = 0; i < size; i++) {
@@ -220,11 +238,21 @@
         }
         mTmpArray.clear();
         mRunningAnimations.clear();
+        mHandler.removeCallbacksAndMessages(null);
     }
 
     private void setPressedSoftware(boolean pressed) {
         if (pressed) {
-            enterSoftware();
+            if (mDelayTouchFeedback) {
+                if (mRunningAnimations.isEmpty()) {
+                    mHandler.removeCallbacksAndMessages(null);
+                    mHandler.postDelayed(this::enterSoftware, ViewConfiguration.getTapTimeout());
+                } else if (mVisible) {
+                    enterSoftware();
+                }
+            } else {
+                enterSoftware();
+            }
         } else {
             exitSoftware();
         }
@@ -232,6 +260,7 @@
 
     private void enterSoftware() {
         cancelAnimations();
+        mVisible = true;
         mGlowAlpha = getMaxGlowAlpha();
         ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(this, "glowScale",
                 0f, GLOW_MAX_SCALE_FACTOR);
@@ -240,6 +269,12 @@
         scaleAnimator.addListener(mAnimatorListener);
         scaleAnimator.start();
         mRunningAnimations.add(scaleAnimator);
+
+        // With the delay, it could eventually animate the enter animation with no pressed state,
+        // then immediately show the exit animation. If this is skipped there will be no ripple.
+        if (mDelayTouchFeedback && !mPressed) {
+            exitSoftware();
+        }
     }
 
     private void exitSoftware() {
@@ -253,7 +288,16 @@
 
     private void setPressedHardware(boolean pressed) {
         if (pressed) {
-            enterHardware();
+            if (mDelayTouchFeedback) {
+                if (mRunningAnimations.isEmpty()) {
+                    mHandler.removeCallbacksAndMessages(null);
+                    mHandler.postDelayed(this::enterHardware, ViewConfiguration.getTapTimeout());
+                } else if (mVisible) {
+                    enterHardware();
+                }
+            } else {
+                enterHardware();
+            }
         } else {
             exitHardware();
         }
@@ -302,6 +346,7 @@
 
     private void enterHardware() {
         cancelAnimations();
+        mVisible = true;
         mDrawingHardwareGlow = true;
         setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2));
         final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(),
@@ -343,6 +388,12 @@
         mRunningAnimations.add(endAnim);
 
         invalidateSelf();
+
+        // With the delay, it could eventually animate the enter animation with no pressed state,
+        // then immediately show the exit animation. If this is skipped there will be no ripple.
+        if (mDelayTouchFeedback && !mPressed) {
+            exitHardware();
+        }
     }
 
     private void exitHardware() {
@@ -366,6 +417,7 @@
         public void onAnimationEnd(Animator animation) {
             mRunningAnimations.remove(animation);
             if (mRunningAnimations.isEmpty() && !mPressed) {
+                mVisible = false;
                 mDrawingHardwareGlow = false;
                 invalidateSelf();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 0501771..077c6c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -284,6 +284,7 @@
     @Override
     public void abortCurrentGesture() {
         setPressed(false);
+        mRipple.abortDelayedRipple();
         mGestureAborted = true;
     }
 
@@ -301,6 +302,11 @@
     }
 
     @Override
+    public void setDelayTouchFeedback(boolean shouldDelay) {
+        mRipple.setDelayTouchFeedback(shouldDelay);
+    }
+
+    @Override
     public void setVertical(boolean vertical) {
         //no op
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
new file mode 100644
index 0000000..acf9c00
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.annotation.ColorInt;
+import android.graphics.drawable.Drawable;
+
+import com.android.internal.graphics.ColorUtils;
+
+/**
+ * Drawable for {@link KeyButtonView}s which contains a single asset and colors for light and dark
+ * navigation bar mode.
+ */
+public class TintedKeyButtonDrawable extends KeyButtonDrawable {
+
+    private final int mLightColor;
+    private final int mDarkColor;
+
+    public static TintedKeyButtonDrawable create(Drawable drawable, @ColorInt int lightColor,
+            @ColorInt int darkColor) {
+        return new TintedKeyButtonDrawable(new Drawable[] { drawable }, lightColor, darkColor);
+    }
+
+    private TintedKeyButtonDrawable(Drawable[] drawables, int lightColor, int darkColor){
+        super(drawables);
+        mLightColor = lightColor;
+        mDarkColor = darkColor;
+    }
+
+    @Override
+    public void setDarkIntensity(float intensity) {
+        // Duplicate intensity scaling from KeyButtonDrawable
+        int intermediateColor = ColorUtils.compositeColors(
+                setAlphaFloat(mDarkColor, intensity),
+                setAlphaFloat(mLightColor,1f - intensity));
+        getDrawable(0).setTint(intermediateColor);
+        invalidateSelf();
+    }
+
+    private int setAlphaFloat(int color, float alpha) {
+        return ColorUtils.setAlphaComponent(color, (int) (alpha * 255f));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index c0241e3..5505099 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -128,12 +128,11 @@
         mDividerHeight = res.getDimensionPixelSize(
                 R.dimen.notification_children_container_divider_height);
         mDividerAlpha = res.getFloat(R.dimen.notification_divider_alpha);
-        mHeaderHeight = res.getDimensionPixelSize(
-                R.dimen.notification_children_container_header_height);
         mNotificationHeaderMargin = res.getDimensionPixelSize(
                 R.dimen.notification_children_container_margin_top);
         mNotificatonTopPadding = res.getDimensionPixelSize(
                 R.dimen.notification_children_container_top_padding);
+        mHeaderHeight = mNotificationHeaderMargin + mNotificatonTopPadding;
         mCollapsedBottompadding = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin_bottom);
         mEnableShadowOnChildNotifications =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 369e7ff..167508a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -76,7 +76,6 @@
 import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.ExpandableOutlineView;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationGuts;
@@ -86,10 +85,8 @@
 import com.android.systemui.statusbar.NotificationSnooze;
 import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -126,16 +123,7 @@
     /**
      * Sentinel value for no current active pointer. Used by {@link #mActivePointerId}.
      */
-    private static final int INVALID_POINTER = -1;
-    private static final AnimatableProperty SIDE_PADDINGS = AnimatableProperty.from(
-            "sidePaddings",
-            NotificationStackScrollLayout::setCurrentSidePadding,
-            NotificationStackScrollLayout::getCurrentSidePadding,
-            R.id.side_padding_animator_tag,
-            R.id.side_padding_animator_end_tag,
-            R.id.side_padding_animator_start_tag);
-    private static final AnimationProperties SIDE_PADDING_PROPERTIES =
-            new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+    private static final int INVALID_POINTER = -1;;
 
     private ExpandHelper mExpandHelper;
     private NotificationSwipeHelper mSwipeHelper;
@@ -143,7 +131,6 @@
     private int mCurrentStackHeight = Integer.MAX_VALUE;
     private final Paint mBackgroundPaint = new Paint();
     private final Path mBackgroundPath = new Path();
-    private final float[] mBackgroundRadii = new float[8];
     private final boolean mShouldDrawNotificationBackground;
 
     private float mExpandedHeight;
@@ -174,7 +161,6 @@
     private int mTopPadding;
     private int mBottomMargin;
     private int mBottomInset = 0;
-    private float mCurrentSidePadding;
 
     /**
      * The algorithm which calculates the properties for our children
@@ -402,7 +388,6 @@
     private boolean mHeadsUpGoingAwayAnimationsAllowed = true;
     private Runnable mAnimateScroll = this::animateScroll;
     private int mCornerRadius;
-    private int mLockscreenSidePaddings;
     private int mSidePaddings;
 
     public NotificationStackScrollLayout(Context context) {
@@ -440,8 +425,7 @@
                 res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
 
         updateWillNotDraw();
-        mBackgroundPaint.setAntiAlias(true);
-        mBackgroundPaint.setStyle(Paint.Style.FILL);
+        mBackgroundPaint.setAntiAlias(true);;
         if (DEBUG) {
             mDebugPaint = new Paint();
             mDebugPaint.setColor(0xffff0000);
@@ -490,7 +474,8 @@
     protected void onDraw(Canvas canvas) {
         if (mShouldDrawNotificationBackground && !mAmbientState.isDark()
                 && mCurrentBounds.top < mCurrentBounds.bottom) {
-            canvas.drawPath(mBackgroundPath, mBackgroundPaint);
+            canvas.drawRoundRect(mSidePaddings, mCurrentBounds.top, getWidth() - mSidePaddings,
+                    mCurrentBounds.bottom, mCornerRadius, mCornerRadius, mBackgroundPaint);
         }
 
         if (DEBUG) {
@@ -543,8 +528,7 @@
                 R.dimen.min_top_overscroll_to_qs);
         mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
         mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom);
-        mLockscreenSidePaddings = res.getDimensionPixelSize(
-                R.dimen.notification_lockscreen_side_paddings);
+        mSidePaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
         mMinInteractionHeight = res.getDimensionPixelSize(
                 R.dimen.notification_min_interaction_height);
         mCornerRadius = res.getDimensionPixelSize(
@@ -575,11 +559,15 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        int childWidthSpec = MeasureSpec.makeMeasureSpec(width - mSidePaddings * 2,
+                MeasureSpec.getMode(widthMeasureSpec));
         // We need to measure all children even the GONE ones, such that the heights are calculated
         // correctly as they are used to calculate how many we can fit on the screen.
         final int size = getChildCount();
         for (int i = 0; i < size; i++) {
-            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
+            measureChild(getChildAt(i), childWidthSpec, heightMeasureSpec);
         }
     }
 
@@ -675,11 +663,32 @@
 
     private void onPreDrawDuringAnimation() {
         mShelf.updateAppearance();
+        updateClippingToTopRoundedCorner();
         if (!mNeedsAnimation && !mChildrenUpdateRequested) {
             updateBackground();
         }
     }
 
+    private void updateClippingToTopRoundedCorner() {
+        Float clipStart = (float) mTopPadding;
+        Float clipEnd = clipStart + mCornerRadius;
+        boolean first = true;
+        for (int i = 0; i < getChildCount(); i++) {
+            ExpandableView child = (ExpandableView) getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+            float start = child.getTranslationY();
+            float end = start + Math.max(child.getActualHeight() - child.getClipBottomAmount(),
+                    0);
+            boolean clip = clipStart > start && clipStart < end
+                    || clipEnd >= start && clipEnd <= end;
+            clip &= !(first && mOwnScrollY == 0);
+            child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0) : -1);
+            first = false;
+        }
+    }
+
     private void updateScrollStateForAddedChildren() {
         if (mChildrenToAddAnimated.isEmpty()) {
             return;
@@ -2255,31 +2264,9 @@
         mScrimController.setExcludedBackgroundArea(
                 mFadingOut || mParentNotFullyVisible || mAmbientState.isDark() || mIsClipped ? null
                         : mCurrentBounds);
-        updateBackgroundPath();
         invalidate();
     }
 
-    private void updateBackgroundPath() {
-        mBackgroundPath.reset();
-        float topRoundness = 0;
-        if (mFirstVisibleBackgroundChild != null) {
-            topRoundness = mFirstVisibleBackgroundChild.getCurrentBackgroundRadiusTop();
-        }
-        topRoundness = onKeyguard() ? mCornerRadius : topRoundness;
-        float bottomRoundNess = mCornerRadius;
-        mBackgroundRadii[0] = topRoundness;
-        mBackgroundRadii[1] = topRoundness;
-        mBackgroundRadii[2] = topRoundness;
-        mBackgroundRadii[3] = topRoundness;
-        mBackgroundRadii[4] = bottomRoundNess;
-        mBackgroundRadii[5] = bottomRoundNess;
-        mBackgroundRadii[6] = bottomRoundNess;
-        mBackgroundRadii[7] = bottomRoundNess;
-        mBackgroundPath.addRoundRect(mCurrentSidePadding, mCurrentBounds.top,
-                getWidth() - mCurrentSidePadding, mCurrentBounds.bottom, mBackgroundRadii,
-                Path.Direction.CCW);
-    }
-
     /**
      * Update the background bounds to the new desired bounds
      */
@@ -2292,8 +2279,8 @@
             mBackgroundBounds.left = mTempInt2[0];
             mBackgroundBounds.right = mTempInt2[0] + getWidth();
         }
-        mBackgroundBounds.left += mCurrentSidePadding;
-        mBackgroundBounds.right -= mCurrentSidePadding;
+        mBackgroundBounds.left += mSidePaddings;
+        mBackgroundBounds.right -= mSidePaddings;
         if (!mIsExpanded) {
             mBackgroundBounds.top = 0;
             mBackgroundBounds.bottom = 0;
@@ -2902,8 +2889,7 @@
 
     private void applyRoundedNess() {
         if (mFirstVisibleBackgroundChild != null) {
-            mFirstVisibleBackgroundChild.setTopRoundness(
-                    mStatusBarState == StatusBarState.KEYGUARD ? 1.0f : 0.0f,
+            mFirstVisibleBackgroundChild.setTopRoundness(1.0f,
                     mFirstVisibleBackgroundChild.isShown()
                             && !mChildrenToAddAnimated.contains(mFirstVisibleBackgroundChild));
         }
@@ -2912,7 +2898,6 @@
                     mLastVisibleBackgroundChild.isShown()
                             && !mChildrenToAddAnimated.contains(mLastVisibleBackgroundChild));
         }
-        updateBackgroundPath();
         invalidate();
     }
 
@@ -2922,7 +2907,6 @@
         generateAddAnimation(child, false /* fromMoreCard */);
         updateAnimationState(child);
         updateChronometerForChild(child);
-        updateCurrentSidePaddings(child);
     }
 
     private void updateHideSensitiveForChild(View child) {
@@ -3021,6 +3005,7 @@
             mAnimationEvents.clear();
             updateBackground();
             updateViewShadows();
+            updateClippingToTopRoundedCorner();
         } else {
             applyCurrentState();
         }
@@ -3714,6 +3699,7 @@
         setAnimationRunning(false);
         updateBackground();
         updateViewShadows();
+        updateClippingToTopRoundedCorner();
     }
 
     private void updateViewShadows() {
@@ -4382,43 +4368,6 @@
     public void setStatusBarState(int statusBarState) {
         mStatusBarState = statusBarState;
         mAmbientState.setStatusBarState(statusBarState);
-        applyRoundedNess();
-        updateSidePaddings();
-    }
-
-    private void updateSidePaddings() {
-        int sidePaddings = mStatusBarState == StatusBarState.KEYGUARD ? mLockscreenSidePaddings : 0;
-        if (sidePaddings != mSidePaddings) {
-            boolean animate = isShown();
-            mSidePaddings = sidePaddings;
-            PropertyAnimator.setProperty(this, SIDE_PADDINGS, sidePaddings,
-                    SIDE_PADDING_PROPERTIES, animate);
-        }
-    }
-
-    protected void setCurrentSidePadding(float sidePadding) {
-        mCurrentSidePadding = sidePadding;
-        updateBackground();
-        applySidePaddingsToChildren();
-    }
-
-    private void applySidePaddingsToChildren() {
-        for (int i = 0; i < getChildCount(); i++) {
-            View view = getChildAt(i);
-            updateCurrentSidePaddings(view);
-        }
-    }
-
-    private void updateCurrentSidePaddings(View view) {
-        if (!(view instanceof ExpandableOutlineView)) {
-            return;
-        }
-        ExpandableOutlineView outlineView = (ExpandableOutlineView) view;
-        outlineView.setCurrentSidePaddings(mCurrentSidePadding);
-    }
-
-    protected float getCurrentSidePadding() {
-        return mCurrentSidePadding;
     }
 
     public void setExpandingVelocity(float expandingVelocity) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index d7c8010..7b91f14 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -413,6 +413,9 @@
             Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, AudioManager.STREAM_RING,
                     mRingerIcon.getTag());
             final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
+            if (ss == null) {
+                return;
+            }
             final boolean hasVibrator = mController.hasVibrator();
             if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
                 if (hasVibrator) {
@@ -617,6 +620,9 @@
     protected void updateRingerH() {
         if (mState != null) {
             final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
+            if (ss == null) {
+                return;
+            }
             switch (mState.ringerModeInternal) {
                 case AudioManager.RINGER_MODE_VIBRATE:
                     mRingerStatus.setText(R.string.volume_ringer_status_vibrate);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index be28569..cd409d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -33,8 +33,13 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+
 import androidx.app.slice.SliceItem;
+import androidx.app.slice.SliceProvider;
+import androidx.app.slice.SliceSpecs;
 import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.widget.SliceLiveData;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -47,6 +52,7 @@
     public void setup() {
         mProvider = new TestableKeyguardSliceProvider();
         mProvider.attachInfo(getContext(), null);
+        SliceProvider.setSpecs(Arrays.asList(SliceSpecs.LIST));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 7f07e0c..3e37cfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -38,6 +38,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.util.NotificationChannels;
 
+import java.util.concurrent.TimeUnit;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -46,6 +47,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class PowerNotificationWarningsTest extends SysuiTestCase {
+
+    public static final String FORMATTED_45M = "0h 45m";
+    public static final String FORMATTED_HOUR = "1h 0m";
     private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
     private PowerNotificationWarnings mPowerNotificationWarnings;
 
@@ -147,4 +151,22 @@
         verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
                 eq(SystemMessage.NOTE_THERMAL_SHUTDOWN), any());
     }
+
+    @Test
+    public void testGetTimeRemainingFormatted_roundsDownTo15() {
+        mPowerNotificationWarnings.updateEstimate(
+                new Estimate(TimeUnit.MINUTES.toMillis(57), true));
+        String time = mPowerNotificationWarnings.getTimeRemainingFormatted();
+
+        assertTrue("time:" + time + ", expected: " + FORMATTED_45M, time.equals(FORMATTED_45M));
+    }
+
+    @Test
+    public void testGetTimeRemainingFormatted_keepsMinutesWhenZero() {
+        mPowerNotificationWarnings.updateEstimate(
+                new Estimate(TimeUnit.MINUTES.toMillis(65), true));
+        String time = mPowerNotificationWarnings.getTimeRemainingFormatted();
+
+        assertTrue("time:" + time + ", expected: " + FORMATTED_HOUR, time.equals(FORMATTED_HOUR));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index e4734a4..fdb7f8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -19,12 +19,15 @@
 import static android.os.HardwarePropertiesManager.TEMPERATURE_SHUTDOWN;
 import static android.provider.Settings.Global.SHOW_TEMPERATURE_WARNING;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.os.BatteryManager;
 import android.os.HardwarePropertiesManager;
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
@@ -37,6 +40,7 @@
 import com.android.systemui.power.PowerUI.WarningsUI;
 import com.android.systemui.statusbar.phone.StatusBar;
 
+import java.util.concurrent.TimeUnit;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -46,14 +50,23 @@
 @SmallTest
 public class PowerUITest extends SysuiTestCase {
 
+    private static final boolean UNPLUGGED = false;
+    private static final boolean POWER_SAVER_OFF = false;
+    private static final int ABOVE_WARNING_BUCKET = 1;
+    public static final int BELOW_WARNING_BUCKET = -1;
+    public static final long BELOW_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(2);
+    public static final long ABOVE_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(4);
     private HardwarePropertiesManager mHardProps;
     private WarningsUI mMockWarnings;
     private PowerUI mPowerUI;
+    private EnhancedEstimates mEnhacedEstimates;
 
     @Before
     public void setup() {
         mMockWarnings = mDependency.injectMockDependency(WarningsUI.class);
+        mEnhacedEstimates = mDependency.injectMockDependency(EnhancedEstimates.class);
         mHardProps = mock(HardwarePropertiesManager.class);
+
         mContext.putComponent(StatusBar.class, mock(StatusBar.class));
         mContext.addMockSystemService(Context.HARDWARE_PROPERTIES_SERVICE, mHardProps);
 
@@ -128,6 +141,180 @@
         verify(mMockWarnings).showHighTemperatureWarning();
     }
 
+    @Test
+    public void testShouldShowLowBatteryWarning_showHybridOnly_returnsShow() {
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        mPowerUI.start();
+
+        // unplugged device that would not show the non-hybrid notification but would show the
+        // hybrid
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        ABOVE_WARNING_BUCKET, Long.MAX_VALUE, BELOW_HYBRID_THRESHOLD,
+                        POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
+        assertTrue(shouldShow);
+    }
+
+    @Test
+    public void testShouldShowLowBatteryWarning_showHybrid_showStandard_returnsShow() {
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        mPowerUI.start();
+
+        // unplugged device that would show the non-hybrid notification and the hybrid
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, Long.MAX_VALUE, BELOW_HYBRID_THRESHOLD,
+                        POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
+        assertTrue(shouldShow);
+    }
+
+    @Test
+    public void testShouldShowLowBatteryWarning_showStandardOnly_returnsShow() {
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        mPowerUI.start();
+
+        // unplugged device that would show the non-hybrid but not the hybrid
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, Long.MAX_VALUE, ABOVE_HYBRID_THRESHOLD,
+                        POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
+        assertTrue(shouldShow);
+    }
+
+    @Test
+    public void testShouldShowLowBatteryWarning_deviceHighBattery_returnsNoShow() {
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        mPowerUI.start();
+
+        // unplugged device that would show the neither due to battery level being good
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, ABOVE_HYBRID_THRESHOLD,
+                        POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
+        assertFalse(shouldShow);
+    }
+
+    @Test
+    public void testShouldShowLowBatteryWarning_devicePlugged_returnsNoShow() {
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        mPowerUI.start();
+
+        // plugged device that would show the neither due to being plugged
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(!UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
+        assertFalse(shouldShow);
+   }
+
+    @Test
+    public void testShouldShowLowBatteryWarning_deviceBatteryStatusUnkown_returnsNoShow() {
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        mPowerUI.start();
+
+        // Unknown battery status device that would show the neither due
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        !POWER_SAVER_OFF, BatteryManager.BATTERY_STATUS_UNKNOWN);
+        assertFalse(shouldShow);
+    }
+
+    @Test
+    public void testShouldShowLowBatteryWarning_batterySaverEnabled_returnsNoShow() {
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        mPowerUI.start();
+
+        // BatterySaverEnabled device that would show the neither due to battery saver
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        !POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
+        assertFalse(shouldShow);
+    }
+
+    @Test
+    public void testShouldDismissLowBatteryWarning_dismissWhenPowerSaverEnabled() {
+        mPowerUI.start();
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        // device that gets power saver turned on should dismiss
+        boolean shouldDismiss =
+                mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, !POWER_SAVER_OFF);
+        assertTrue(shouldDismiss);
+    }
+
+    @Test
+    public void testShouldDismissLowBatteryWarning_dismissWhenPlugged() {
+        mPowerUI.start();
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+
+        // device that gets plugged in should dismiss
+        boolean shouldDismiss =
+                mPowerUI.shouldDismissLowBatteryWarning(!UNPLUGGED, BELOW_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, POWER_SAVER_OFF);
+        assertTrue(shouldDismiss);
+    }
+
+    @Test
+    public void testShouldDismissLowBatteryWarning_dismissHybridSignal_showStandardSignal_shouldShow() {
+        mPowerUI.start();
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        // would dismiss hybrid but not non-hybrid should not dismiss
+        boolean shouldDismiss =
+                mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, POWER_SAVER_OFF);
+        assertFalse(shouldDismiss);
+    }
+
+    @Test
+    public void testShouldDismissLowBatteryWarning_showHybridSignal_dismissStandardSignal_shouldShow() {
+        mPowerUI.start();
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+
+        // would dismiss non-hybrid but not hybrid should not dismiss
+        boolean shouldDismiss =
+                mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET,
+                        ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, POWER_SAVER_OFF);
+        assertFalse(shouldDismiss);
+    }
+
+    @Test
+    public void testShouldDismissLowBatteryWarning_showBothSignal_shouldShow() {
+        mPowerUI.start();
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+
+        // should not dismiss when both would not dismiss
+        boolean shouldDismiss =
+                mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, POWER_SAVER_OFF);
+        assertFalse(shouldDismiss);
+    }
+
+    @Test
+    public void testShouldDismissLowBatteryWarning_dismissBothSignal_shouldDismiss() {
+        mPowerUI.start();
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+
+        //should dismiss if both would dismiss
+        boolean shouldDismiss =
+                mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET,
+                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, POWER_SAVER_OFF);
+        assertTrue(shouldDismiss);
+    }
+
+    @Test
+    public void testShouldDismissLowBatteryWarning_dismissStandardSignal_hybridDisabled_shouldDismiss() {
+        mPowerUI.start();
+        when(mEnhacedEstimates.isHybridNotificationEnabled()).thenReturn(false);
+
+        // would dismiss non-hybrid with hybrid disabled should dismiss
+        boolean shouldDismiss =
+                mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET,
+                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, POWER_SAVER_OFF);
+        assertTrue(shouldDismiss);
+    }
+
     private void setCurrentTemp(float temp) {
         when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_CURRENT))
                 .thenReturn(new float[] { temp });
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 6721938..d77bf69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -16,11 +16,13 @@
 
 package com.android.systemui.statusbar;
 
+import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.Mockito.any;
@@ -50,11 +52,11 @@
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
+import android.testing.PollingCheck;
 import android.testing.UiThreadTest;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
-import android.widget.Switch;
 import android.widget.TextView;
 
 import com.android.systemui.R;
@@ -66,7 +68,6 @@
 import org.mockito.ArgumentCaptor;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -117,50 +118,31 @@
 
         // Some test channels.
         mNotificationChannel = new NotificationChannel(
-                TEST_CHANNEL, TEST_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
+                TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
         mDefaultNotificationChannel = new NotificationChannel(
                 NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME,
-                NotificationManager.IMPORTANCE_LOW);
+                IMPORTANCE_LOW);
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
                 new Notification(), UserHandle.CURRENT, null, 0);
     }
 
-    private CharSequence getStringById(int resId) {
-        return mContext.getString(resId);
+    // TODO: if tests are taking too long replace this with something that makes the animation
+    // finish instantly.
+    private void waitForUndoButton() {
+        PollingCheck.waitFor(1000,
+                () -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility());
     }
-
-    private CharSequence getNumChannelsDescString(int numChannels) {
-        return String.format(
-                mContext.getResources().getQuantityString(
-                        R.plurals.notification_num_channels_desc, numChannels),
-                numChannels);
-    }
-
-    private CharSequence getChannelsListDescString(NotificationChannel... channels) {
-        if (channels.length == 2) {
-            return mContext.getString(R.string.notification_channels_list_desc_2,
-                    channels[0].getName(), channels[1].getName());
-        } else {
-            final int numOthers = channels.length - 2;
-            return String.format(
-                    mContext.getResources().getQuantityString(
-                            R.plurals.notification_channels_list_desc_2_and_others, numOthers),
-                    channels[0].getName(), channels[1].getName(), numOthers);
-        }
-    }
-
-    private CharSequence getNumChannelsString(int numChannels) {
-        return mContext.getString(R.string.notification_num_channels, numChannels);
+    private void waitForStopButton() {
+        PollingCheck.waitFor(1000,
+                () -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility());
     }
 
     @Test
     public void testBindNotification_SetsTextApplicationName() throws Exception {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.pkgname);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+        final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
         assertTrue(textView.getText().toString().contains("App Name"));
     }
 
@@ -170,24 +152,19 @@
         when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
                 .thenReturn(iconDrawable);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final ImageView iconView = (ImageView) mNotificationInfo.findViewById(R.id.pkgicon);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+        final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
         assertEquals(iconDrawable, iconView.getDrawable());
     }
 
     @Test
     public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name);
-        assertEquals(View.GONE, groupNameView.getVisibility());
-        final TextView groupDividerView =
-                (TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider);
-        assertEquals(View.GONE, groupDividerView.getVisibility());
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+        final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
+        assertEquals(GONE, groupNameView.getVisibility());
+        final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider);
+        assertEquals(GONE, groupDividerView.getVisibility());
     }
 
     @Test
@@ -199,75 +176,50 @@
                 eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
                 .thenReturn(notificationChannelGroup);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+        final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(View.VISIBLE, groupNameView.getVisibility());
         assertEquals("Test Group Name", groupNameView.getText());
-        final TextView groupDividerView =
-                (TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider);
+        final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider);
         assertEquals(View.VISIBLE, groupDividerView.getVisibility());
     }
 
     @Test
     public void testBindNotification_SetsTextChannelName() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+        final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(TEST_CHANNEL_NAME, textView.getText());
     }
 
     @Test
     public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
-        assertEquals(mContext.getString(R.string.notification_header_default_channel),
-                textView.getText());
+                TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, null);
+        final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
+        assertEquals(GONE, textView.getVisibility());
     }
 
     @Test
-    public void testBindNotification_UnblockablePackageDoesNotUseChannelName() throws Exception {
+    public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, Collections.singleton(TEST_PACKAGE_NAME));
-        final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
-        assertEquals(mContext.getString(R.string.notification_header_default_channel),
-                textView.getText());
-    }
-
-    @Test
-    public void testBindNotification_DefaultChannelUsesNameWhenMoreThanOneChannelExists()
-            throws Exception {
-        when(mMockINotificationManager.getNumNotificationChannelsForPackage(
-                eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
-        assertEquals(mDefaultNotificationChannel.getName(), textView.getText());
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+                Collections.singleton(TEST_PACKAGE_NAME));
+        final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
+        assertEquals(VISIBLE, textView.getVisibility());
     }
 
     @Test
     public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
                     latch.countDown();
-                }, null, null, null, null);
+                }, null, null);
 
-        final TextView settingsButton =
-                (TextView) mNotificationInfo.findViewById(R.id.more_settings);
+        final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         settingsButton.performClick();
         // Verify that listener was triggered.
         assertEquals(0, latch.getCount());
@@ -276,24 +228,20 @@
     @Test
     public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
-        final TextView settingsButton =
-                (TextView) mNotificationInfo.findViewById(R.id.more_settings);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+        final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
     }
 
     @Test
-    public void testBindNotification_SettingsButtonReappersAfterSecondBind() throws Exception {
+    public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn,
-                (View v, NotificationChannel c, int appUid) -> {}, null, null, null, null);
-        final TextView settingsButton =
-                (TextView) mNotificationInfo.findViewById(R.id.more_settings);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
+                (View v, NotificationChannel c, int appUid) -> {
+                }, null, null);
+        final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertEquals(View.VISIBLE, settingsButton.getVisibility());
     }
 
@@ -301,279 +249,63 @@
     public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME,
-                Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn,
+                TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(null, c);
                     latch.countDown();
-                }, null, null, null, null);
+                }, null, null);
 
-        final TextView settingsButton =
-                (TextView) mNotificationInfo.findViewById(R.id.more_settings);
-        settingsButton.performClick();
+        mNotificationInfo.findViewById(R.id.info).performClick();
         // Verify that listener was triggered.
         assertEquals(0, latch.getCount());
     }
 
     @Test
-    public void testBindNotification_SettingsTextWithOneChannel() throws Exception {
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn,
-                (View v, NotificationChannel c, int appUid) -> {
-                }, null, null, null, null);
-        final TextView settingsButton =
-                (TextView) mNotificationInfo.findViewById(R.id.more_settings);
-        assertEquals(getStringById(R.string.notification_more_settings), settingsButton.getText());
-    }
-
-    @Test
-    public void testBindNotification_SettingsTextWithMultipleChannels() throws Exception {
-        when(mMockINotificationManager.getNumNotificationChannelsForPackage(
-                eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn,
-                (View v, NotificationChannel c, int appUid) -> {
-                }, null, null, null, null);
-        final TextView settingsButton =
-                (TextView) mNotificationInfo.findViewById(R.id.more_settings);
-        assertEquals(getStringById(R.string.notification_all_categories), settingsButton.getText());
-    }
-
-    @Test
-    public void testBindNotification_SettingsTextWithMultipleChannelsForUnblockableApp()
-            throws Exception {
-        when(mMockINotificationManager.getNumNotificationChannelsForPackage(
-                eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn,
-                (View v, NotificationChannel c, int appUid) -> {
-                }, null, null, null, Collections.singleton(TEST_PACKAGE_NAME));
-        final TextView settingsButton =
-                (TextView) mNotificationInfo.findViewById(R.id.more_settings);
-        assertEquals(getStringById(R.string.notification_more_settings), settingsButton.getText());
-    }
-
-    @Test
-    public void testBindNotification_SetsOnClickListenerForDone() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null,
-                null, (View v) -> {
-                    latch.countDown();
-                },
-                null, null);
-
-        final TextView doneButton = (TextView) mNotificationInfo.findViewById(R.id.done);
-        doneButton.performClick();
-        // Verify that listener was triggered.
-        assertEquals(0, latch.getCount());
-    }
-
-    @Test
-    public void testBindNotification_NumChannelsTextHiddenWhenDefaultChannel() throws Exception {
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null,
-                null, null, null);
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(View.INVISIBLE, numChannelsView.getVisibility());
-    }
-
-    @Test
-    public void testBindNotification_NumChannelsTextDisplaysWhenMoreThanOneChannelExists()
-            throws Exception {
-        when(mMockINotificationManager.getNumNotificationChannelsForPackage(
-                eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null,
-                null, null, null);
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(numChannelsView.getVisibility(), View.VISIBLE);
-        assertEquals(getNumChannelsDescString(2), numChannelsView.getText());
-    }
-
-    @Test
-    public void testBindNotification_NumChannelsTextDisplaysWhenNotDefaultChannel()
-            throws Exception {
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(numChannelsView.getVisibility(), View.VISIBLE);
-        assertEquals(getNumChannelsDescString(1), numChannelsView.getText());
-    }
-
-    @Test
-    public void testBindNotification_NumChannelsTextScalesWithNumberOfChannels()
-            throws Exception {
-        when(mMockINotificationManager.getNumNotificationChannelsForPackage(
-                eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(getNumChannelsDescString(2), numChannelsView.getText());
-    }
-
-    @Test
     @UiThreadTest
-    public void testBindNotification_NumChannelsTextListsChannelsWhenTwoInBundle()
+    public void testBindNotification_ChannelNameInvisibleWhenBundleFromDifferentChannels()
             throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel),
-                numChannelsView.getText());
-    }
-
-    @Test
-    @UiThreadTest
-    public void testBindNotification_NumChannelsTextListsChannelsWhenThreeInBundle()
-            throws Exception {
-        NotificationChannel thirdChannel = new NotificationChannel(
-                "third_channel", "third_channel", NotificationManager.IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME,
-                Arrays.asList(mNotificationChannel, mDefaultNotificationChannel, thirdChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(
-                getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel,
-                        thirdChannel),
-                numChannelsView.getText());
-    }
-
-    @Test
-    @UiThreadTest
-    public void testBindNotification_NumChannelsTextListsChannelsWhenFourInBundle()
-            throws Exception {
-        NotificationChannel thirdChannel = new NotificationChannel(
-                "third_channel", "third_channel", NotificationManager.IMPORTANCE_LOW);
-        NotificationChannel fourthChannel = new NotificationChannel(
-                "fourth_channel", "fourth_channel", NotificationManager.IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME,
-                Arrays.asList(mNotificationChannel, mDefaultNotificationChannel, thirdChannel,
-                        fourthChannel), mNotificationChannel.getImportance(), mSbn, null, null,
-                null, null, null);
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(
-                getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel,
-                        thirdChannel, fourthChannel),
-                numChannelsView.getText());
-    }
-
-    @Test
-    @UiThreadTest
-    public void testBindNotification_ChannelNameChangesWhenBundleFromDifferentChannels()
-            throws Exception {
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
+                TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null, null, null, null);
         final TextView channelNameView =
-                (TextView) mNotificationInfo.findViewById(R.id.channel_name);
-        assertEquals(getNumChannelsString(2), channelNameView.getText());
+                mNotificationInfo.findViewById(R.id.channel_name);
+        assertEquals(GONE, channelNameView.getVisibility());
     }
 
     @Test
     @UiThreadTest
-    public void testEnabledSwitchInvisibleIfBundleFromDifferentChannels() throws Exception {
+    public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
-    }
-
-    @Test
-    public void testbindNotification_ChannelDisabledTextGoneWhenNotDisabled() throws Exception {
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
-        final TextView channelDisabledView =
-                (TextView) mNotificationInfo.findViewById(R.id.channel_disabled);
-        assertEquals(channelDisabledView.getVisibility(), View.GONE);
-    }
-
-    @Test
-    public void testbindNotification_ChannelDisabledTextVisibleWhenDisabled() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-        final TextView channelDisabledView =
-                (TextView) mNotificationInfo.findViewById(R.id.channel_disabled);
-        assertEquals(channelDisabledView.getVisibility(), View.VISIBLE);
-        // Replaces the numChannelsView
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(numChannelsView.getVisibility(), View.GONE);
+                TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null, null, null, null);
+        final TextView blockView = mNotificationInfo.findViewById(R.id.block);
+        assertEquals(GONE, blockView.getVisibility());
     }
 
     @Test
     public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
                 null, Collections.singleton(TEST_PACKAGE_NAME));
-        final TextView numChannelsView =
-                (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertEquals(View.VISIBLE, numChannelsView.getVisibility());
+        final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
+        assertEquals(View.VISIBLE, view.getVisibility());
         assertEquals(mContext.getString(R.string.notification_unblockable_desc),
-                numChannelsView.getText());
-    }
-
-    @Test
-    @UiThreadTest
-    public void testBindNotification_ChannelDisabledTextShowsForDefaultChannel()
-            throws Exception {
-        mDefaultNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
-                mDefaultNotificationChannel.getImportance(), mSbn, null, null,
-                null, null, null);
-        final TextView channelDisabledView =
-                (TextView) mNotificationInfo.findViewById(R.id.channel_disabled);
-        assertEquals(View.VISIBLE, channelDisabledView.getVisibility());
+                view.getText());
     }
 
     @Test
     public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), eq(TEST_UID), any());
     }
 
     @Test
     public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
 
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        enabledSwitch.setChecked(false);
+        mNotificationInfo.findViewById(R.id.block).performClick();
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), eq(TEST_UID), any());
     }
@@ -582,9 +314,7 @@
     public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged()
             throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
 
         mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -596,9 +326,7 @@
             throws Exception {
         mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
 
         mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -606,114 +334,25 @@
     }
 
     @Test
-    public void testEnabledSwitchOnByDefault() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        assertTrue(enabledSwitch.isChecked());
-    }
-
-    @Test
-    public void testEnabledButtonOffWhenAlreadyBanned() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        assertFalse(enabledSwitch.isChecked());
-    }
-
-    @Test
-    public void testEnabledSwitchVisibleByDefault() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        assertEquals(View.VISIBLE, enabledSwitch.getVisibility());
-    }
-
-    @Test
-    public void testEnabledSwitchInvisibleIfNonBlockable() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, Collections.singleton(TEST_PACKAGE_NAME));
-
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
-    }
-
-    @Test
-    public void testEnabledSwitchInvisibleIfNonBlockableSystemChannel() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        mNotificationChannel.setBlockableSystem(false);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_SYSTEM_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
-    }
-
-    @Test
-    public void testEnabledSwitchVisibleIfBlockableSystemChannel() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        mNotificationChannel.setBlockableSystem(true);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_SYSTEM_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, null);
-
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        assertEquals(View.VISIBLE, enabledSwitch.getVisibility());
-    }
-
-    @Test
-    public void testEnabledSwitchInvisibleIfMultiChannelSummary() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        mNotificationChannel.setBlockableSystem(true);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, Collections.singleton(TEST_PACKAGE_NAME));
-
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
-    }
-
-    @Test
     public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
                 null, Collections.singleton(TEST_PACKAGE_NAME));
-        mNotificationInfo.handleCloseControls(true, false);
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), eq(TEST_UID), any());
     }
 
     @Test
-    public void testEnabledSwitchChangedCallsUpdateNotificationChannel() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+    public void testBlockChangedCallsUpdateNotificationChannel() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, Collections.singleton(TEST_PACKAGE_NAME));
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
 
-        Switch enabledSwitch = mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        enabledSwitch.setChecked(false);
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
 
         ArgumentCaptor<NotificationChannel> updated =
@@ -725,15 +364,35 @@
     }
 
     @Test
-    public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+    public void testBlockUndoDoesNotCallUpdateNotificationChannel() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
-                null, Collections.singleton(TEST_PACKAGE_NAME));
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+                Collections.singleton(TEST_PACKAGE_NAME));
 
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        enabledSwitch.setChecked(false);
+
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.undo).performClick();
+        waitForStopButton();
+        mNotificationInfo.handleCloseControls(true, false);
+
+        ArgumentCaptor<NotificationChannel> updated =
+                ArgumentCaptor.forClass(NotificationChannel.class);
+        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+                anyString(), eq(TEST_UID), updated.capture());
+        assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+    }
+
+    @Test
+    public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+                Collections.singleton(TEST_PACKAGE_NAME));
+
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
         mNotificationInfo.handleCloseControls(false, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
@@ -741,16 +400,14 @@
 
     @Test
     public void testCloseControlsDoesNotUpdateIfCheckSaveListenerIsNoOp() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
                 (Runnable saveImportance, StatusBarNotification sbn) -> {
-                },
-                Collections.singleton(TEST_PACKAGE_NAME));
+                }, null, null, Collections.singleton(TEST_PACKAGE_NAME));
 
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        enabledSwitch.setChecked(false);
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
@@ -758,17 +415,15 @@
 
     @Test
     public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception {
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), mSbn, null, null, null,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
                 (Runnable saveImportance, StatusBarNotification sbn) -> {
                     saveImportance.run();
-                },
-                Collections.singleton(TEST_PACKAGE_NAME));
+                }, null, null, null);
 
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        enabledSwitch.setChecked(false);
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
                 eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
@@ -785,22 +440,19 @@
         List<ResolveInfo> ris = new ArrayList<>();
         ris.add(ri);
         when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris);
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
                 .setSettingsText(settingsText).build();
         StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
                 0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
 
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), sbn, null,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null,
                 (View v, Intent intent) -> {
                     latch.countDown();
-                }, null, null, null);
+                }, null);
         final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
         assertEquals(View.VISIBLE, settingsLink.getVisibility());
-        assertTrue(settingsLink.getText().toString().length() > settingsText.length());
-        assertTrue(settingsLink.getText().toString().contains(settingsText));
         settingsLink.performClick();
         assertEquals(0, latch.getCount());
     }
@@ -816,17 +468,17 @@
         List<ResolveInfo> ris = new ArrayList<>();
         ris.add(ri);
         when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris);
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
                 .setSettingsText(settingsText).build();
         StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
                 0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
 
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
-                mNotificationChannel.getImportance(), sbn, null, (View v, Intent intent) -> {
+                TEST_PACKAGE_NAME, mNotificationChannel, 2, sbn, null, null,
+                (View v, Intent intent) -> {
                     latch.countDown();
-                }, null, null, null);
+                }, null);
         final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
         assertEquals(View.VISIBLE, settingsLink.getVisibility());
         settingsLink.performClick();
@@ -837,18 +489,16 @@
     public void testNoSettingsLink_noHandlingActivity() throws Exception {
         final String settingsText = "work chats";
         when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(null);
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
                 .setSettingsText(settingsText).build();
         StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
                 0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
 
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), sbn, null, null, null,
-                null, null);
+                TEST_PACKAGE_NAME, mNotificationChannel, 2, sbn, null, null, null, null);
         final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
-        assertEquals(View.GONE, settingsLink.getVisibility());
+        assertEquals(GONE, settingsLink.getVisibility());
     }
 
     @Test
@@ -860,52 +510,17 @@
         List<ResolveInfo> ris = new ArrayList<>();
         ris.add(ri);
         when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris);
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         Notification n = new Notification.Builder(mContext, mNotificationChannel.getId()).build();
         StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
                 0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
 
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), sbn, null, null, null,
-                null, null);
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, null);
         final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
-        assertEquals(View.GONE, settingsLink.getVisibility());
+        assertEquals(GONE, settingsLink.getVisibility());
     }
 
-    @Test
-    public void testNoSettingsLink_afterBlockingChannel() throws Exception {
-        final String settingsText = "work chats";
-        final ResolveInfo ri = new ResolveInfo();
-        ri.activityInfo = new ActivityInfo();
-        ri.activityInfo.packageName = TEST_PACKAGE_NAME;
-        ri.activityInfo.name = "something";
-        List<ResolveInfo> ris = new ArrayList<>();
-        ris.add(ri);
-        when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris);
-        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
-                .setSettingsText(settingsText).build();
-        StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
-                0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
-
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
-                mNotificationChannel.getImportance(), sbn, null, null, null,
-                null, null);
-        final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
-        assertEquals(View.VISIBLE, settingsLink.getVisibility());
-
-        // Block channel
-        Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
-        enabledSwitch.setChecked(false);
-
-        assertEquals(View.GONE, settingsLink.getVisibility());
-
-        //unblock
-        enabledSwitch.setChecked(true);
-        assertEquals(View.VISIBLE, settingsLink.getVisibility());
-    }
 
     @Test
     public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {
diff --git a/packages/VpnDialogs/res/values-pl/strings.xml b/packages/VpnDialogs/res/values-pl/strings.xml
index be6a4c2..d5201d7 100644
--- a/packages/VpnDialogs/res/values-pl/strings.xml
+++ b/packages/VpnDialogs/res/values-pl/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Żądanie połączenia"</string>
-    <string name="warning" msgid="809658604548412033">"Aplikacja <xliff:g id="APP">%s</xliff:g> chce utworzyć połączenie VPN, które pozwoli jej na monitorowanie ruchu sieciowego. Zaakceptuj, tylko jeśli masz zaufanie do źródła. Gdy sieć VPN jest aktywna, u góry ekranu pojawia się &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" msgid="809658604548412033">"Aplikacja <xliff:g id="APP">%s</xliff:g> chce utworzyć połączenie VPN, które pozwoli jej na monitorowanie ruchu sieciowego. Zaakceptuj, tylko jeśli masz zaufanie do źródła. &lt;br /&gt; &lt;br /&gt;Gdy sieć VPN jest aktywna, u góry ekranu pojawia się &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"Połączono z VPN"</string>
     <string name="session" msgid="6470628549473641030">"Sesja:"</string>
     <string name="duration" msgid="3584782459928719435">"Czas trwania:"</string>
diff --git a/packages/VpnDialogs/res/values-ru/strings.xml b/packages/VpnDialogs/res/values-ru/strings.xml
index b9207a0..35ae7f7 100644
--- a/packages/VpnDialogs/res/values-ru/strings.xml
+++ b/packages/VpnDialogs/res/values-ru/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Запрос на подключение"</string>
-    <string name="warning" msgid="809658604548412033">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" пытается подключиться к сети VPN, чтобы отслеживать трафик. Этот запрос следует принимать, только если вы доверяете источнику.<br/><br/>Когда подключение VPN активно, в верхней части экрана появляется значок &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" msgid="809658604548412033">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" пытается подключиться к сети VPN, чтобы отслеживать трафик. Этот запрос следует принимать, только если вы доверяете источнику. &lt;br /&gt; &lt;br /&gt;Когда подключение VPN активно, в верхней части экрана появляется значок &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN-подключение установлено"</string>
     <string name="session" msgid="6470628549473641030">"Сеанс:"</string>
     <string name="duration" msgid="3584782459928719435">"Продолжительность:"</string>
diff --git a/packages/VpnDialogs/res/values-zh-rCN/strings.xml b/packages/VpnDialogs/res/values-zh-rCN/strings.xml
index 2815312..0bd62ce 100644
--- a/packages/VpnDialogs/res/values-zh-rCN/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rCN/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"网络连接请求"</string>
-    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g>想要设置一个VPN连接(可被用于监控网络流量)。请只在您信任该来源的情况下才接受此请求。在VPN处于活动状态时,您的屏幕顶部会显示 &lt;img src=vpn_icon /&gt; 图标。"</string>
+    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g>想要设置一个 VPN 连接,以允许其监控网络流量。除非您信任该来源,否则请勿接受此请求。启用 VPN 时,您的屏幕顶部会显示 &lt;img src=vpn_icon /&gt; 图标。"</string>
     <string name="legacy_title" msgid="192936250066580964">"已连接VPN"</string>
     <string name="session" msgid="6470628549473641030">"会话:"</string>
     <string name="duration" msgid="3584782459928719435">"时长:"</string>
diff --git a/packages/overlays/DisplayCutoutEmulationOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationOverlay/Android.mk
new file mode 100644
index 0000000..f4205ad6
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationOverlay/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := DisplayCutoutEmulation
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := DisplayCutoutEmulationOverlay
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/DisplayCutoutEmulationOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..dd43690
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationOverlay/AndroidManifest.xml
@@ -0,0 +1,8 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.internal.display.cutout.emulation"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <overlay android:targetPackage="android" android:priority="1"/>
+
+    <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/DisplayCutoutEmulationOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationOverlay/res/values/config.xml
new file mode 100644
index 0000000..88c19c7
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationOverlay/res/values/config.xml
@@ -0,0 +1,44 @@
+<!--
+  ~ 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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- The bounding path of the cutout region of the main built-in display.
+         Must either be empty if there is no cutout region, or a string that is parsable by
+         {@link android.util.PathParser}. -->
+    <string translatable="false" name="config_mainBuiltInDisplayCutout">
+        M 687.0,0
+        l -66,50
+        l 0,50
+        l 66,50
+        l 66,0
+        l 66,-50
+        l 0,-50
+        l -66,-50
+        z
+    </string>
+
+    <!-- Whether the display cutout region of the main built-in display should be forced to
+     black in software (to avoid aliasing or emulate a cutout that is not physically existent).
+     -->
+    <bool name="config_fillMainBuiltInDisplayCutout">true</bool>
+
+    <!-- Height of the status bar -->
+    <dimen name="status_bar_height">150px</dimen>
+
+</resources>
+
+
diff --git a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl b/packages/overlays/DisplayCutoutEmulationOverlay/res/values/strings.xml
similarity index 60%
copy from core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl
copy to packages/overlays/DisplayCutoutEmulationOverlay/res/values/strings.xml
index fe13179..5d5c425 100644
--- a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl
+++ b/packages/overlays/DisplayCutoutEmulationOverlay/res/values/strings.xml
@@ -1,11 +1,13 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
+<?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
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,8 +15,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-package android.security.recoverablekeystore;
+    <string name="display_cutout_emulation_overlay">Display Cutout Emulation</string>
 
-/* @hide */
-parcelable KeyDerivationParameters;
+</resources>
+
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 4f04d36..04cee67 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5129,6 +5129,21 @@
     // OS: P
     FUELGAUGE_SMART_BATTERY = 1281;
 
+    // ACTION: User tapped Screenshot in the power menu.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: P
+    ACTION_SCREENSHOT_POWER_MENU = 1282;
+
+    // OPEN: Settings > Apps & Notifications -> Special app access -> Storage Access
+    // CATEGORY: SETTINGS
+    // OS: P
+    STORAGE_ACCESS = 1283;
+
+    // OPEN: Settings > Apps & Notifications -> Special app access -> Storage Access -> Package
+    // CATEGORY: SETTINGS
+    // OS: P
+    APPLICATIONS_STORAGE_DETAIL = 1284;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ba8ce59..fc6058c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1280,7 +1280,7 @@
         }
 
         int servicePackageUid = serviceInfo.applicationInfo.uid;
-        if (mAppOpsManager.noteOpNoThrow(AppOpsManager.OP_BIND_ACCESSIBILITY_SERVICE,
+        if (mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE,
                 servicePackageUid, serviceInfo.packageName) != AppOpsManager.MODE_ALLOWED) {
             Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName(
                     serviceInfo.packageName, serviceInfo.name).flattenToShortString()
@@ -1362,14 +1362,13 @@
     private int computeRelevantEventTypes(UserState userState, Client client) {
         int relevantEventTypes = 0;
 
-        int numBoundServices = userState.mBoundServices.size();
-        for (int i = 0; i < numBoundServices; i++) {
-            AccessibilityServiceConnection service =
-                    userState.mBoundServices.get(i);
+        // Use iterator for thread-safety
+        for (AccessibilityServiceConnection service : userState.mBoundServices) {
             relevantEventTypes |= isClientInPackageWhitelist(service.getServiceInfo(), client)
                     ? service.getRelevantEventTypes()
                     : 0;
         }
+
         relevantEventTypes |= isClientInPackageWhitelist(
                 mUiAutomationManager.getServiceInfo(), client)
                 ? mUiAutomationManager.getRelevantEventTypes()
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 74d2ddd..0a03b7f 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -17,6 +17,7 @@
 package com.android.server.accessibility;
 
 import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
@@ -364,7 +365,7 @@
 
                 persistScaleAndTransitionTo(mViewportDraggingState);
 
-            } else if (action == ACTION_UP) {
+            } else if (action == ACTION_UP || action == ACTION_CANCEL) {
 
                 persistScaleAndTransitionTo(mDetectingState);
 
@@ -496,7 +497,9 @@
                     }
                 }
                 break;
-                case ACTION_UP: {
+
+                case ACTION_UP:
+                case ACTION_CANCEL: {
                     if (!mZoomedInBeforeDrag) zoomOff();
                     clear();
                     transitionTo(mDetectingState);
@@ -533,12 +536,15 @@
 
         @Override
         public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-            if (event.getActionMasked() == ACTION_UP) {
-                transitionTo(mDetectingState);
-            }
+            switch (event.getActionMasked()) {
+                case ACTION_UP:
+                case ACTION_CANCEL: {
+                    transitionTo(mDetectingState);
+                } break;
 
-            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-                mLastDelegatedDownEventTime = event.getDownTime();
+                case ACTION_DOWN: {
+                    mLastDelegatedDownEventTime = event.getDownTime();
+                } break;
             }
             if (getNext() != null) {
                 // We cache some events to see if the user wants to trigger magnification.
diff --git a/services/backup/java/com/android/server/backup/BackupPolicyEnforcer.java b/services/backup/java/com/android/server/backup/BackupPolicyEnforcer.java
new file mode 100644
index 0000000..158084a
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/BackupPolicyEnforcer.java
@@ -0,0 +1,25 @@
+package com.android.server.backup;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A helper class to decouple this service from {@link DevicePolicyManager} in order to improve
+ * testability.
+ */
+@VisibleForTesting
+public class BackupPolicyEnforcer {
+    private DevicePolicyManager mDevicePolicyManager;
+
+    public BackupPolicyEnforcer(Context context) {
+        mDevicePolicyManager =
+                (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+    }
+
+    public ComponentName getMandatoryBackupTransport() {
+        return mDevicePolicyManager.getMandatoryBackupTransport();
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 03591a8..f33ec55 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -38,6 +38,7 @@
 import android.app.IActivityManager;
 import android.app.IBackupAgent;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.app.backup.BackupManager;
 import android.app.backup.BackupManagerMonitor;
 import android.app.backup.FullBackup;
@@ -207,6 +208,10 @@
     public static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED";
     public static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName";
 
+    // Time delay for initialization operations that can be delayed so as not to consume too much CPU
+    // on bring-up and increase time-to-UI.
+    private static final long INITIALIZATION_DELAY_MILLIS = 3000;
+
     // Timeout interval for deciding that a bind or clear-data has taken too long
     private static final long TIMEOUT_INTERVAL = 10 * 1000;
 
@@ -282,6 +287,9 @@
 
     private final BackupPasswordManager mBackupPasswordManager;
 
+    // Time when we post the transport registration operation
+    private final long mRegisterTransportsRequestedTime;
+
     @GuardedBy("mPendingRestores")
     private boolean mIsRestoreInProgress;
     @GuardedBy("mPendingRestores")
@@ -674,6 +682,8 @@
     @GuardedBy("mQueueLock")
     private ArrayList<FullBackupEntry> mFullBackupQueue;
 
+    private BackupPolicyEnforcer mBackupPolicyEnforcer;
+
     // Utility: build a new random integer token. The low bits are the ordinal of the
     // operation for near-time uniqueness, and the upper bits are random for app-
     // side unpredictability.
@@ -735,6 +745,9 @@
         // Set up our transport options and initialize the default transport
         SystemConfig systemConfig = SystemConfig.getInstance();
         Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
+        if (transportWhitelist == null) {
+            transportWhitelist = Collections.emptySet();
+        }
 
         String transport =
                 Settings.Secure.getString(
@@ -749,8 +762,7 @@
                 new TransportManager(
                         context,
                         transportWhitelist,
-                        transport,
-                        backupThread.getLooper());
+                        transport);
 
         // If encrypted file systems is enabled or disabled, this call will return the
         // correct directory.
@@ -852,15 +864,19 @@
         }
 
         mTransportManager = transportManager;
-        mTransportManager.setTransportBoundListener(mTransportBoundListener);
-        mTransportManager.registerAllTransports();
+        mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered);
+        mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime();
+        mBackupHandler.postDelayed(
+                mTransportManager::registerTransports, INITIALIZATION_DELAY_MILLIS);
 
-        // Now that we know about valid backup participants, parse any
-        // leftover journal files into the pending backup set
-        mBackupHandler.post(this::parseLeftoverJournals);
+        // Now that we know about valid backup participants, parse any leftover journal files into
+        // the pending backup set
+        mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
 
         // Power management
         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
+
+        mBackupPolicyEnforcer = new BackupPolicyEnforcer(context);
     }
 
     private void initPackageTracking() {
@@ -1151,39 +1167,28 @@
         }
     }
 
-    private TransportManager.TransportBoundListener mTransportBoundListener =
-            new TransportManager.TransportBoundListener() {
-                @Override
-                public boolean onTransportBound(IBackupTransport transport) {
-                    // If the init sentinel file exists, we need to be sure to perform the init
-                    // as soon as practical.  We also create the state directory at registration
-                    // time to ensure it's present from the outset.
-                    String name = null;
-                    try {
-                        name = transport.name();
-                        String transportDirName = transport.transportDirName();
-                        File stateDir = new File(mBaseStateDir, transportDirName);
-                        stateDir.mkdirs();
+    private void onTransportRegistered(String transportName, String transportDirName) {
+        if (DEBUG) {
+            long timeMs = SystemClock.elapsedRealtime() - mRegisterTransportsRequestedTime;
+            Slog.d(TAG, "Transport " + transportName + " registered " + timeMs
+                    + "ms after first request (delay = " + INITIALIZATION_DELAY_MILLIS + "ms)");
+        }
 
-                        File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
-                        if (initSentinel.exists()) {
-                            synchronized (mQueueLock) {
-                                mPendingInits.add(name);
+        File stateDir = new File(mBaseStateDir, transportDirName);
+        stateDir.mkdirs();
 
-                                // TODO: pick a better starting time than now + 1 minute
-                                long delay = 1000 * 60; // one minute, in milliseconds
-                                mAlarmManager.set(AlarmManager.RTC_WAKEUP,
-                                        System.currentTimeMillis() + delay, mRunInitIntent);
-                            }
-                        }
-                        return true;
-                    } catch (Exception e) {
-                        // the transport threw when asked its file naming prefs; declare it invalid
-                        Slog.w(TAG, "Failed to regiser transport: " + name);
-                        return false;
-                    }
-                }
-            };
+        File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
+        if (initSentinel.exists()) {
+            synchronized (mQueueLock) {
+                mPendingInits.add(transportName);
+
+                // TODO: pick a better starting time than now + 1 minute
+                long delay = 1000 * 60; // one minute, in milliseconds
+                mAlarmManager.set(AlarmManager.RTC_WAKEUP,
+                        System.currentTimeMillis() + delay, mRunInitIntent);
+            }
+        }
+    }
 
     // ----- Track installation/removal of packages -----
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -2774,6 +2779,10 @@
     public void setBackupEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupEnabled");
+        if (!enable && mBackupPolicyEnforcer.getMandatoryBackupTransport() != null) {
+            Slog.w(TAG, "Cannot disable backups when the mandatory backups policy is active.");
+            return;
+        }
 
         Slog.i(TAG, "Backup enabled => " + enable);
 
@@ -2891,14 +2900,14 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "listAllTransports");
 
-        return mTransportManager.getBoundTransportNames();
+        return mTransportManager.getRegisteredTransportNames();
     }
 
     @Override
     public ComponentName[] listAllTransportComponents() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "listAllTransportComponents");
-        return mTransportManager.getAllTransportComponents();
+        return mTransportManager.getRegisteredTransportComponents();
     }
 
     @Override
@@ -3003,10 +3012,18 @@
 
     /** Selects transport {@code transportName} and returns previous selected transport. */
     @Override
+    @Deprecated
+    @Nullable
     public String selectBackupTransport(String transportName) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BACKUP, "selectBackupTransport");
 
+        if (!isAllowedByMandatoryBackupTransportPolicy(transportName)) {
+            // Don't change the transport if it is not allowed.
+            Slog.w(TAG, "Failed to select transport - disallowed by device owner policy.");
+            return mTransportManager.getCurrentTransportName();
+        }
+
         final long oldId = Binder.clearCallingIdentity();
         try {
             String previousTransportName = mTransportManager.selectTransport(transportName);
@@ -3021,10 +3038,20 @@
 
     @Override
     public void selectBackupTransportAsync(
-            ComponentName transportComponent, ISelectBackupTransportCallback listener) {
+            ComponentName transportComponent, @Nullable ISelectBackupTransportCallback listener) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BACKUP, "selectBackupTransportAsync");
-
+        if (!isAllowedByMandatoryBackupTransportPolicy(transportComponent)) {
+            try {
+                if (listener != null) {
+                    Slog.w(TAG, "Failed to select transport - disallowed by device owner policy.");
+                    listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "ISelectBackupTransportCallback listener not available");
+            }
+            return;
+        }
         final long oldId = Binder.clearCallingIdentity();
         try {
             String transportString = transportComponent.flattenToShortString();
@@ -3046,10 +3073,12 @@
                         }
 
                         try {
-                            if (transportName != null) {
-                                listener.onSuccess(transportName);
-                            } else {
-                                listener.onFailure(result);
+                            if (listener != null) {
+                                if (transportName != null) {
+                                    listener.onSuccess(transportName);
+                                } else {
+                                    listener.onFailure(result);
+                                }
                             }
                         } catch (RemoteException e) {
                             Slog.e(TAG, "ISelectBackupTransportCallback listener not available");
@@ -3060,6 +3089,38 @@
         }
     }
 
+    /**
+     * Returns if the specified transport can be set as the current transport without violating the
+     * mandatory backup transport policy.
+     */
+    private boolean isAllowedByMandatoryBackupTransportPolicy(String transportName) {
+        ComponentName mandatoryBackupTransport = mBackupPolicyEnforcer.getMandatoryBackupTransport();
+        if (mandatoryBackupTransport == null) {
+            return true;
+        }
+        final String mandatoryBackupTransportName;
+        try {
+            mandatoryBackupTransportName =
+                    mTransportManager.getTransportName(mandatoryBackupTransport);
+        } catch (TransportNotRegisteredException e) {
+            Slog.e(TAG, "mandatory backup transport not registered!");
+            return false;
+        }
+        return TextUtils.equals(mandatoryBackupTransportName, transportName);
+    }
+
+    /**
+     * Returns if the specified transport can be set as the current transport without violating the
+     * mandatory backup transport policy.
+     */
+    private boolean isAllowedByMandatoryBackupTransportPolicy(ComponentName transport) {
+        ComponentName mandatoryBackupTransport = mBackupPolicyEnforcer.getMandatoryBackupTransport();
+        if (mandatoryBackupTransport == null) {
+            return true;
+        }
+        return mandatoryBackupTransport.equals(transport);
+    }
+
     private void updateStateForTransport(String newTransportName) {
         // Publish the name change
         Settings.Secure.putString(mContext.getContentResolver(),
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 34b8935..09456b68 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -16,93 +16,56 @@
 
 package com.android.server.backup;
 
-import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
-
 import android.annotation.Nullable;
+import android.annotation.WorkerThread;
 import android.app.backup.BackupManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.backup.IBackupTransport;
+import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
+import com.android.server.backup.transport.OnTransportRegisteredListener;
 import com.android.server.backup.transport.TransportClient;
 import com.android.server.backup.transport.TransportClientManager;
 import com.android.server.backup.transport.TransportConnectionListener;
 import com.android.server.backup.transport.TransportNotAvailableException;
 import com.android.server.backup.transport.TransportNotRegisteredException;
 
-import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
-/**
- * Handles in-memory bookkeeping of all BackupTransport objects.
- */
+/** Handles in-memory bookkeeping of all BackupTransport objects. */
 public class TransportManager {
-
     private static final String TAG = "BackupTransportManager";
 
     @VisibleForTesting
     public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
 
-    private static final long REBINDING_TIMEOUT_UNPROVISIONED_MS = 30 * 1000; // 30 sec
-    private static final long REBINDING_TIMEOUT_PROVISIONED_MS = 5 * 60 * 1000; // 5 mins
-    private static final int REBINDING_TIMEOUT_MSG = 1;
-
     private final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
     private final Context mContext;
     private final PackageManager mPackageManager;
     private final Set<ComponentName> mTransportWhitelist;
-    private final Handler mHandler;
     private final TransportClientManager mTransportClientManager;
-
-    /**
-     * This listener is called after we bind to any transport. If it returns true, this is a valid
-     * transport.
-     */
-    private TransportBoundListener mTransportBoundListener;
-
     private final Object mTransportLock = new Object();
-
-    /**
-     * We have detected these transports on the device. Unless in exceptional cases, we are also
-     * bound to all of these.
-     */
-    @GuardedBy("mTransportLock")
-    private final Map<ComponentName, TransportConnection> mValidTransports = new ArrayMap<>();
-
-    /** We are currently bound to these transports. */
-    @GuardedBy("mTransportLock")
-    private final Map<String, ComponentName> mBoundTransports = new ArrayMap<>();
-
-    /** @see #getEligibleTransportComponents() */
-    @GuardedBy("mTransportLock")
-    private final Set<ComponentName> mEligibleTransports = new ArraySet<>();
+    private OnTransportRegisteredListener mOnTransportRegisteredListener = (c, n) -> {};
 
     /** @see #getRegisteredTransportNames() */
     @GuardedBy("mTransportLock")
@@ -110,120 +73,98 @@
             new ArrayMap<>();
 
     @GuardedBy("mTransportLock")
+    @Nullable
     private volatile String mCurrentTransportName;
 
-    TransportManager(
-            Context context,
-            Set<ComponentName> whitelist,
-            String defaultTransport,
-            TransportBoundListener listener,
-            Looper looper) {
-        this(context, whitelist, defaultTransport, looper);
-        mTransportBoundListener = listener;
+    TransportManager(Context context, Set<ComponentName> whitelist, String selectedTransport) {
+        this(context, whitelist, selectedTransport, new TransportClientManager(context));
     }
 
+    @VisibleForTesting
     TransportManager(
             Context context,
             Set<ComponentName> whitelist,
-            String defaultTransport,
-            Looper looper) {
+            String selectedTransport,
+            TransportClientManager transportClientManager) {
         mContext = context;
         mPackageManager = context.getPackageManager();
-        if (whitelist != null) {
-            mTransportWhitelist = whitelist;
-        } else {
-            mTransportWhitelist = new ArraySet<>();
-        }
-        mCurrentTransportName = defaultTransport;
-        mHandler = new RebindOnTimeoutHandler(looper);
-        mTransportClientManager = new TransportClientManager(context);
+        mTransportWhitelist = Preconditions.checkNotNull(whitelist);
+        mCurrentTransportName = selectedTransport;
+        mTransportClientManager = transportClientManager;
     }
 
-    public void setTransportBoundListener(TransportBoundListener transportBoundListener) {
-        mTransportBoundListener = transportBoundListener;
+    /* Sets a listener to be called whenever a transport is registered. */
+    public void setOnTransportRegisteredListener(OnTransportRegisteredListener listener) {
+        mOnTransportRegisteredListener = listener;
     }
 
+    @WorkerThread
     void onPackageAdded(String packageName) {
-        // New package added. Bind to all transports it contains.
-        synchronized (mTransportLock) {
-            log_verbose("Package added. Binding to all transports. " + packageName);
-            bindToAllInternal(packageName, null /* all components */);
-        }
+        registerTransportsFromPackage(packageName, transportComponent -> true);
     }
 
     void onPackageRemoved(String packageName) {
-        // Package removed. Remove all its transports from our list. These transports have already
-        // been removed from mBoundTransports because onServiceDisconnected would already been
-        // called on TransportConnection objects.
         synchronized (mTransportLock) {
-            Iterator<Map.Entry<ComponentName, TransportConnection>> iter =
-                    mValidTransports.entrySet().iterator();
-            while (iter.hasNext()) {
-                Map.Entry<ComponentName, TransportConnection> validTransport = iter.next();
-                ComponentName componentName = validTransport.getKey();
-                if (componentName.getPackageName().equals(packageName)) {
-                    TransportConnection transportConnection = validTransport.getValue();
-                    iter.remove();
-                    if (transportConnection != null) {
-                        mContext.unbindService(transportConnection);
-                        log_verbose("Package removed, removing transport: "
-                                + componentName.flattenToShortString());
-                    }
-                }
-            }
-            removeTransportsIfLocked(
-                    componentName -> packageName.equals(componentName.getPackageName()));
+            mRegisteredTransportsDescriptionMap.keySet().removeIf(fromPackageFilter(packageName));
         }
     }
 
-    void onPackageChanged(String packageName, String[] components) {
+    @WorkerThread
+    void onPackageChanged(String packageName, String... components) {
         synchronized (mTransportLock) {
-            // Remove all changed components from mValidTransports. We'll bind to them again
-            // and re-add them if still valid.
-            Set<ComponentName> transportsToBeRemoved = new ArraySet<>();
-            for (String component : components) {
-                ComponentName componentName = new ComponentName(packageName, component);
-                transportsToBeRemoved.add(componentName);
-                TransportConnection removed = mValidTransports.remove(componentName);
-                if (removed != null) {
-                    mContext.unbindService(removed);
-                    log_verbose("Package changed. Removing transport: " +
-                            componentName.flattenToShortString());
-                }
-            }
-            removeTransportsIfLocked(transportsToBeRemoved::contains);
-            bindToAllInternal(packageName, components);
+            Set<ComponentName> transportComponents =
+                    Stream.of(components)
+                            .map(component -> new ComponentName(packageName, component))
+                            .collect(Collectors.toSet());
+
+            mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
+            registerTransportsFromPackage(packageName, transportComponents::contains);
         }
     }
 
-    @GuardedBy("mTransportLock")
-    private void removeTransportsIfLocked(Predicate<ComponentName> filter) {
-        mEligibleTransports.removeIf(filter);
-        mRegisteredTransportsDescriptionMap.keySet().removeIf(filter);
-    }
-
-    public IBackupTransport getTransportBinder(String transportName) {
+    /**
+     * Returns the {@link ComponentName}s of the registered transports.
+     *
+     * <p>A *registered* transport is a transport that satisfies intent with action
+     * android.backup.TRANSPORT_HOST, returns true for {@link #isTransportTrusted(ComponentName)}
+     * and that we have successfully connected to once.
+     */
+    ComponentName[] getRegisteredTransportComponents() {
         synchronized (mTransportLock) {
-            ComponentName component = mBoundTransports.get(transportName);
-            if (component == null) {
-                Slog.w(TAG, "Transport " + transportName + " not bound.");
-                return null;
-            }
-            TransportConnection conn = mValidTransports.get(component);
-            if (conn == null) {
-                Slog.w(TAG, "Transport " + transportName + " not valid.");
-                return null;
-            }
-            return conn.getBinder();
+            return mRegisteredTransportsDescriptionMap
+                    .keySet()
+                    .toArray(new ComponentName[mRegisteredTransportsDescriptionMap.size()]);
         }
     }
 
-    public IBackupTransport getCurrentTransportBinder() {
-        return getTransportBinder(mCurrentTransportName);
+    /**
+     * Returns the names of the registered transports.
+     *
+     * @see #getRegisteredTransportComponents()
+     */
+    String[] getRegisteredTransportNames() {
+        synchronized (mTransportLock) {
+            return mRegisteredTransportsDescriptionMap
+                    .values()
+                    .stream()
+                    .map(transportDescription -> transportDescription.name)
+                    .toArray(String[]::new);
+        }
+    }
+
+    /** Returns a set with the whitelisted transports. */
+    Set<ComponentName> getTransportWhitelist() {
+        return mTransportWhitelist;
+    }
+
+    @Nullable
+    String getCurrentTransportName() {
+        return mCurrentTransportName;
     }
 
     /**
      * Returns the transport name associated with {@code transportComponent}.
+     *
      * @throws TransportNotRegisteredException if the transport is not registered.
      */
     public String getTransportName(ComponentName transportComponent)
@@ -234,7 +175,32 @@
     }
 
     /**
-     * Retrieve the configuration intent of {@code transportName}.
+     * Retrieves the transport dir name of {@code transportComponent}.
+     *
+     * @throws TransportNotRegisteredException if the transport is not registered.
+     */
+    public String getTransportDirName(ComponentName transportComponent)
+            throws TransportNotRegisteredException {
+        synchronized (mTransportLock) {
+            return getRegisteredTransportDescriptionOrThrowLocked(transportComponent)
+                    .transportDirName;
+        }
+    }
+
+    /**
+     * Retrieves the transport dir name of {@code transportName}.
+     *
+     * @throws TransportNotRegisteredException if the transport is not registered.
+     */
+    public String getTransportDirName(String transportName) throws TransportNotRegisteredException {
+        synchronized (mTransportLock) {
+            return getRegisteredTransportDescriptionOrThrowLocked(transportName).transportDirName;
+        }
+    }
+
+    /**
+     * Retrieves the configuration intent of {@code transportName}.
+     *
      * @throws TransportNotRegisteredException if the transport is not registered.
      */
     @Nullable
@@ -247,7 +213,21 @@
     }
 
     /**
-     * Retrieve the data management intent of {@code transportName}.
+     * Retrieves the current destination string of {@code transportName}.
+     *
+     * @throws TransportNotRegisteredException if the transport is not registered.
+     */
+    public String getTransportCurrentDestinationString(String transportName)
+            throws TransportNotRegisteredException {
+        synchronized (mTransportLock) {
+            return getRegisteredTransportDescriptionOrThrowLocked(transportName)
+                    .currentDestinationString;
+        }
+    }
+
+    /**
+     * Retrieves the data management intent of {@code transportName}.
+     *
      * @throws TransportNotRegisteredException if the transport is not registered.
      */
     @Nullable
@@ -260,19 +240,8 @@
     }
 
     /**
-     * Retrieve the current destination string of {@code transportName}.
-     * @throws TransportNotRegisteredException if the transport is not registered.
-     */
-    public String getTransportCurrentDestinationString(String transportName)
-            throws TransportNotRegisteredException {
-        synchronized (mTransportLock) {
-            return getRegisteredTransportDescriptionOrThrowLocked(transportName)
-                    .currentDestinationString;
-        }
-    }
-
-    /**
-     * Retrieve the data management label of {@code transportName}.
+     * Retrieves the data management label of {@code transportName}.
+     *
      * @throws TransportNotRegisteredException if the transport is not registered.
      */
     @Nullable
@@ -284,54 +253,74 @@
         }
     }
 
-    /**
-     * Retrieve the transport dir name of {@code transportName}.
-     * @throws TransportNotRegisteredException if the transport is not registered.
-     */
-    public String getTransportDirName(String transportName)
-            throws TransportNotRegisteredException {
+    /* Returns true if the transport identified by {@code transportName} is registered. */
+    public boolean isTransportRegistered(String transportName) {
         synchronized (mTransportLock) {
-            return getRegisteredTransportDescriptionOrThrowLocked(transportName)
-                    .transportDirName;
-        }
-    }
-
-    /**
-     * Retrieve the transport dir name of {@code transportComponent}.
-     * @throws TransportNotRegisteredException if the transport is not registered.
-     */
-    public String getTransportDirName(ComponentName transportComponent)
-            throws TransportNotRegisteredException {
-        synchronized (mTransportLock) {
-            return getRegisteredTransportDescriptionOrThrowLocked(transportComponent)
-                    .transportDirName;
+            return getRegisteredTransportEntryLocked(transportName) != null;
         }
     }
 
     /**
      * Execute {@code transportConsumer} for each registered transport passing the transport name.
      * This is called with an internal lock held, ensuring that the transport will remain registered
-     * while {@code transportConsumer} is being executed. Don't do heavy operations in
-     * {@code transportConsumer}.
+     * while {@code transportConsumer} is being executed. Don't do heavy operations in {@code
+     * transportConsumer}.
      */
     public void forEachRegisteredTransport(Consumer<String> transportConsumer) {
         synchronized (mTransportLock) {
-            for (TransportDescription transportDescription
-                    : mRegisteredTransportsDescriptionMap.values()) {
+            for (TransportDescription transportDescription :
+                    mRegisteredTransportsDescriptionMap.values()) {
                 transportConsumer.accept(transportDescription.name);
             }
         }
     }
 
-    public String getTransportName(IBackupTransport binder) {
+    /**
+     * Updates given values for the transport already registered and identified with {@param
+     * transportComponent}. If the transport is not registered it will log and return.
+     */
+    public void updateTransportAttributes(
+            ComponentName transportComponent,
+            String name,
+            @Nullable Intent configurationIntent,
+            String currentDestinationString,
+            @Nullable Intent dataManagementIntent,
+            @Nullable String dataManagementLabel) {
         synchronized (mTransportLock) {
-            for (TransportConnection conn : mValidTransports.values()) {
-                if (conn.getBinder() == binder) {
-                    return conn.getName();
-                }
+            TransportDescription description =
+                    mRegisteredTransportsDescriptionMap.get(transportComponent);
+            if (description == null) {
+                Slog.e(TAG, "Transport " + name + " not registered tried to change description");
+                return;
             }
+            description.name = name;
+            description.configurationIntent = configurationIntent;
+            description.currentDestinationString = currentDestinationString;
+            description.dataManagementIntent = dataManagementIntent;
+            description.dataManagementLabel = dataManagementLabel;
+            Slog.d(TAG, "Transport " + name + " updated its attributes");
         }
-        return null;
+    }
+
+    @GuardedBy("mTransportLock")
+    private TransportDescription getRegisteredTransportDescriptionOrThrowLocked(
+            ComponentName transportComponent) throws TransportNotRegisteredException {
+        TransportDescription description =
+                mRegisteredTransportsDescriptionMap.get(transportComponent);
+        if (description == null) {
+            throw new TransportNotRegisteredException(transportComponent);
+        }
+        return description;
+    }
+
+    @GuardedBy("mTransportLock")
+    private TransportDescription getRegisteredTransportDescriptionOrThrowLocked(
+            String transportName) throws TransportNotRegisteredException {
+        TransportDescription description = getRegisteredTransportDescriptionLocked(transportName);
+        if (description == null) {
+            throw new TransportNotRegisteredException(transportName);
+        }
+        return description;
     }
 
     @GuardedBy("mTransportLock")
@@ -351,21 +340,11 @@
     }
 
     @GuardedBy("mTransportLock")
-    private TransportDescription getRegisteredTransportDescriptionOrThrowLocked(
-            String transportName) throws TransportNotRegisteredException {
-        TransportDescription description = getRegisteredTransportDescriptionLocked(transportName);
-        if (description == null) {
-            throw new TransportNotRegisteredException(transportName);
-        }
-        return description;
-    }
-
-    @GuardedBy("mTransportLock")
     @Nullable
     private Map.Entry<ComponentName, TransportDescription> getRegisteredTransportEntryLocked(
             String transportName) {
-        for (Map.Entry<ComponentName, TransportDescription> entry
-                : mRegisteredTransportsDescriptionMap.entrySet()) {
+        for (Map.Entry<ComponentName, TransportDescription> entry :
+                mRegisteredTransportsDescriptionMap.entrySet()) {
             TransportDescription description = entry.getValue();
             if (transportName.equals(description.name)) {
                 return entry;
@@ -374,17 +353,16 @@
         return null;
     }
 
-    @GuardedBy("mTransportLock")
-    private TransportDescription getRegisteredTransportDescriptionOrThrowLocked(
-            ComponentName transportComponent) throws TransportNotRegisteredException {
-        TransportDescription description =
-                mRegisteredTransportsDescriptionMap.get(transportComponent);
-        if (description == null) {
-            throw new TransportNotRegisteredException(transportComponent);
-        }
-        return description;
-    }
-
+    /**
+     * Returns a {@link TransportClient} for {@code transportName} or {@code null} if not
+     * registered.
+     *
+     * @param transportName The name of the transport.
+     * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
+     *     {@link TransportClient#connectAsync(TransportConnectionListener, String)} for more
+     *     details.
+     * @return A {@link TransportClient} or null if not registered.
+     */
     @Nullable
     public TransportClient getTransportClient(String transportName, String caller) {
         try {
@@ -395,6 +373,16 @@
         }
     }
 
+    /**
+     * Returns a {@link TransportClient} for {@code transportName} or throws if not registered.
+     *
+     * @param transportName The name of the transport.
+     * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
+     *     {@link TransportClient#connectAsync(TransportConnectionListener, String)} for more
+     *     details.
+     * @return A {@link TransportClient}.
+     * @throws TransportNotRegisteredException if the transport is not registered.
+     */
     public TransportClient getTransportClientOrThrow(String transportName, String caller)
             throws TransportNotRegisteredException {
         synchronized (mTransportLock) {
@@ -406,19 +394,14 @@
         }
     }
 
-    public boolean isTransportRegistered(String transportName) {
-        synchronized (mTransportLock) {
-            return getRegisteredTransportEntryLocked(transportName) != null;
-        }
-    }
-
     /**
-     * Returns a {@link TransportClient} for the current transport or null if not found.
+     * Returns a {@link TransportClient} for the current transport or {@code null} if not
+     * registered.
      *
      * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
      *     {@link TransportClient#connectAsync(TransportConnectionListener, String)} for more
      *     details.
-     * @return A {@link TransportClient} or null if not found.
+     * @return A {@link TransportClient} or null if not registered.
      */
     @Nullable
     public TransportClient getCurrentTransportClient(String caller) {
@@ -455,130 +438,88 @@
         mTransportClientManager.disposeOfTransportClient(transportClient, caller);
     }
 
-    String[] getBoundTransportNames() {
-        synchronized (mTransportLock) {
-            return mBoundTransports.keySet().toArray(new String[mBoundTransports.size()]);
-        }
-    }
-
-    ComponentName[] getAllTransportComponents() {
-        synchronized (mTransportLock) {
-            return mValidTransports.keySet().toArray(new ComponentName[mValidTransports.size()]);
-        }
-    }
-
     /**
-     * An *eligible* transport is a service component that satisfies intent with action
-     * android.backup.TRANSPORT_HOST and returns true for
-     * {@link #isTransportTrusted(ComponentName)}. It may be registered or not registered.
-     * This method returns the {@link ComponentName}s of those transports.
-     */
-    ComponentName[] getEligibleTransportComponents() {
-        synchronized (mTransportLock) {
-            return mEligibleTransports.toArray(new ComponentName[mEligibleTransports.size()]);
-        }
-    }
-
-    Set<ComponentName> getTransportWhitelist() {
-        return mTransportWhitelist;
-    }
-
-    /**
-     * A *registered* transport is an eligible transport that has been successfully connected and
-     * that returned true for method
-     * {@link TransportBoundListener#onTransportBound(IBackupTransport)} of TransportBoundListener
-     * provided in the constructor. This method returns the names of the registered transports.
-     */
-    String[] getRegisteredTransportNames() {
-        synchronized (mTransportLock) {
-            return mRegisteredTransportsDescriptionMap.values().stream()
-                    .map(transportDescription -> transportDescription.name)
-                    .toArray(String[]::new);
-        }
-    }
-
-    /**
-     * Updates given values for the transport already registered and identified with
-     * {@param transportComponent}. If the transport is not registered it will log and return.
-     */
-    public void updateTransportAttributes(
-            ComponentName transportComponent,
-            String name,
-            @Nullable Intent configurationIntent,
-            String currentDestinationString,
-            @Nullable Intent dataManagementIntent,
-            @Nullable String dataManagementLabel) {
-        synchronized (mTransportLock) {
-            TransportDescription description =
-                    mRegisteredTransportsDescriptionMap.get(transportComponent);
-            if (description == null) {
-                Slog.e(TAG, "Transport " + name + " not registered tried to change description");
-                return;
-            }
-            description.name = name;
-            description.configurationIntent = configurationIntent;
-            description.currentDestinationString = currentDestinationString;
-            description.dataManagementIntent = dataManagementIntent;
-            description.dataManagementLabel = dataManagementLabel;
-            Slog.d(TAG, "Transport " + name + " updated its attributes");
-        }
-    }
-
-    @Nullable
-    String getCurrentTransportName() {
-        return mCurrentTransportName;
-    }
-
-    // This is for mocking, Mockito can't mock if package-protected and in the same package but
-    // different class loaders. Checked with the debugger and class loaders are different
-    // See https://github.com/mockito/mockito/issues/796
-    @VisibleForTesting(visibility = PACKAGE)
-    public void registerAllTransports() {
-        bindToAllInternal(null /* all packages */, null /* all components */);
-    }
-
-    /**
-     * Bind to all transports belonging to the given package and the given component list.
-     * null acts a wildcard.
+     * Sets {@code transportName} as selected transport and returns previously selected transport
+     * name. If there was no previous transport it returns null.
      *
-     * If packageName is null, bind to all transports in all packages.
-     * If components is null, bind to all transports in the given package.
+     * <p>You should NOT call this method in new code. This won't make any checks against {@code
+     * transportName}, putting any operation at risk of a {@link TransportNotRegisteredException} or
+     * another error at the time it's being executed.
+     *
+     * <p>{@link Deprecated} as public, this method can be used as private.
      */
-    private void bindToAllInternal(String packageName, String[] components) {
-        PackageInfo pkgInfo = null;
-        if (packageName != null) {
+    @Deprecated
+    @Nullable
+    String selectTransport(String transportName) {
+        synchronized (mTransportLock) {
+            String prevTransport = mCurrentTransportName;
+            mCurrentTransportName = transportName;
+            return prevTransport;
+        }
+    }
+
+    /**
+     * Tries to register the transport if not registered. If successful also selects the transport.
+     *
+     * @param transportComponent Host of the transport.
+     * @return One of {@link BackupManager#SUCCESS}, {@link BackupManager#ERROR_TRANSPORT_INVALID}
+     *     or {@link BackupManager#ERROR_TRANSPORT_UNAVAILABLE}.
+     */
+    @WorkerThread
+    public int registerAndSelectTransport(ComponentName transportComponent) {
+        synchronized (mTransportLock) {
+            if (!mRegisteredTransportsDescriptionMap.containsKey(transportComponent)) {
+                int result = registerTransport(transportComponent);
+                if (result != BackupManager.SUCCESS) {
+                    return result;
+                }
+            }
+
             try {
-                pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
-            } catch (PackageManager.NameNotFoundException e) {
-                Slog.w(TAG, "Package not found: " + packageName);
-                return;
+                selectTransport(getTransportName(transportComponent));
+                return BackupManager.SUCCESS;
+            } catch (TransportNotRegisteredException e) {
+                // Shouldn't happen because we are holding the lock
+                Slog.wtf(TAG, "Transport unexpectedly not registered");
+                return BackupManager.ERROR_TRANSPORT_UNAVAILABLE;
             }
         }
+    }
 
-        Intent intent = new Intent(mTransportServiceIntent);
-        if (packageName != null) {
-            intent.setPackage(packageName);
+    @WorkerThread
+    public void registerTransports() {
+        registerTransportsForIntent(mTransportServiceIntent, transportComponent -> true);
+    }
+
+    @WorkerThread
+    private void registerTransportsFromPackage(
+            String packageName, Predicate<ComponentName> transportComponentFilter) {
+        try {
+            mPackageManager.getPackageInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.e(TAG, "Trying to register transports from package not found " + packageName);
+            return;
         }
 
-        List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
-                intent, 0, UserHandle.USER_SYSTEM);
-        if (hosts != null) {
+        registerTransportsForIntent(
+                new Intent(mTransportServiceIntent).setPackage(packageName),
+                transportComponentFilter.and(fromPackageFilter(packageName)));
+    }
+
+    @WorkerThread
+    private void registerTransportsForIntent(
+            Intent intent, Predicate<ComponentName> transportComponentFilter) {
+        List<ResolveInfo> hosts =
+                mPackageManager.queryIntentServicesAsUser(intent, 0, UserHandle.USER_SYSTEM);
+        if (hosts == null) {
+            return;
+        }
+        synchronized (mTransportLock) {
             for (ResolveInfo host : hosts) {
-                final ComponentName infoComponentName = getComponentName(host.serviceInfo);
-                boolean shouldBind = false;
-                if (components != null && packageName != null) {
-                    for (String component : components) {
-                        ComponentName cn = new ComponentName(pkgInfo.packageName, component);
-                        if (infoComponentName.equals(cn)) {
-                            shouldBind = true;
-                            break;
-                        }
-                    }
-                } else {
-                    shouldBind = true;
-                }
-                if (shouldBind && isTransportTrusted(infoComponentName)) {
-                    tryBindTransport(infoComponentName);
+                ComponentName transportComponent = host.serviceInfo.getComponentName();
+                if (transportComponentFilter.test(transportComponent)
+                        && isTransportTrusted(transportComponent)) {
+                    registerTransport(transportComponent);
                 }
             }
         }
@@ -605,64 +546,6 @@
         return true;
     }
 
-    private void tryBindTransport(ComponentName transportComponentName) {
-        Slog.d(TAG, "Binding to transport: " + transportComponentName.flattenToShortString());
-        // TODO: b/22388012 (Multi user backup and restore)
-        TransportConnection connection = new TransportConnection(transportComponentName);
-        synchronized (mTransportLock) {
-            mEligibleTransports.add(transportComponentName);
-        }
-        if (bindToTransport(transportComponentName, connection)) {
-            synchronized (mTransportLock) {
-                mValidTransports.put(transportComponentName, connection);
-            }
-        } else {
-            Slog.w(TAG, "Couldn't bind to transport " + transportComponentName);
-        }
-    }
-
-    private boolean bindToTransport(ComponentName componentName, ServiceConnection connection) {
-        Intent intent = new Intent(mTransportServiceIntent)
-                .setComponent(componentName);
-        return mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
-                createSystemUserHandle());
-    }
-
-    String selectTransport(String transportName) {
-        synchronized (mTransportLock) {
-            String prevTransport = mCurrentTransportName;
-            mCurrentTransportName = transportName;
-            return prevTransport;
-        }
-    }
-
-    /**
-     * Tries to register the transport if not registered. If successful also selects the transport.
-     *
-     * @param transportComponent Host of the transport.
-     * @return One of {@link BackupManager#SUCCESS}, {@link BackupManager#ERROR_TRANSPORT_INVALID}
-     *     or {@link BackupManager#ERROR_TRANSPORT_UNAVAILABLE}.
-     */
-    public int registerAndSelectTransport(ComponentName transportComponent) {
-        synchronized (mTransportLock) {
-            if (!mRegisteredTransportsDescriptionMap.containsKey(transportComponent)) {
-                int result = registerTransport(transportComponent);
-                if (result != BackupManager.SUCCESS) {
-                    return result;
-                }
-            }
-
-            try {
-                selectTransport(getTransportName(transportComponent));
-                return BackupManager.SUCCESS;
-            } catch (TransportNotRegisteredException e) {
-                // Shouldn't happen because we are holding the lock
-                Slog.wtf(TAG, "Transport unexpectedly not registered");
-                return BackupManager.ERROR_TRANSPORT_UNAVAILABLE;
-            }
-        }
-    }
-
     /**
      * Tries to register transport represented by {@code transportComponent}.
      *
@@ -670,7 +553,12 @@
      * @return One of {@link BackupManager#SUCCESS}, {@link BackupManager#ERROR_TRANSPORT_INVALID}
      *     or {@link BackupManager#ERROR_TRANSPORT_UNAVAILABLE}.
      */
+    @WorkerThread
     private int registerTransport(ComponentName transportComponent) {
+        if (!isTransportTrusted(transportComponent)) {
+            return BackupManager.ERROR_TRANSPORT_INVALID;
+        }
+
         String transportString = transportComponent.flattenToShortString();
 
         String callerLogString = "TransportManager.registerTransport()";
@@ -689,26 +577,21 @@
         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, transportString, 1);
 
         int result;
-        if (isTransportValid(transport)) {
-            try {
-                registerTransport(transportComponent, transport);
-                // If registerTransport() hasn't thrown...
-                result = BackupManager.SUCCESS;
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Transport " + transportString + " died while registering");
-                result = BackupManager.ERROR_TRANSPORT_UNAVAILABLE;
-            }
-        } else {
-            Slog.w(TAG, "Can't register invalid transport " + transportString);
-            result = BackupManager.ERROR_TRANSPORT_INVALID;
+        try {
+            String transportName = transport.name();
+            String transportDirName = transport.transportDirName();
+            registerTransport(transportComponent, transport);
+            // If registerTransport() hasn't thrown...
+            Slog.d(TAG, "Transport " + transportString + " registered");
+            mOnTransportRegisteredListener.onTransportRegistered(transportName, transportDirName);
+            result = BackupManager.SUCCESS;
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Transport " + transportString + " died while registering");
+            EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, transportString, 0);
+            result = BackupManager.ERROR_TRANSPORT_UNAVAILABLE;
         }
 
         mTransportClientManager.disposeOfTransportClient(transportClient, callerLogString);
-        if (result == BackupManager.SUCCESS) {
-            Slog.d(TAG, "Transport " + transportString + " registered");
-        } else {
-            EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, transportString, 0);
-        }
         return result;
     }
 
@@ -717,204 +600,20 @@
             throws RemoteException {
         synchronized (mTransportLock) {
             String name = transport.name();
-            TransportDescription description = new TransportDescription(
-                    name,
-                    transport.transportDirName(),
-                    transport.configurationIntent(),
-                    transport.currentDestinationString(),
-                    transport.dataManagementIntent(),
-                    transport.dataManagementLabel());
+            TransportDescription description =
+                    new TransportDescription(
+                            name,
+                            transport.transportDirName(),
+                            transport.configurationIntent(),
+                            transport.currentDestinationString(),
+                            transport.dataManagementIntent(),
+                            transport.dataManagementLabel());
             mRegisteredTransportsDescriptionMap.put(transportComponent, description);
         }
     }
 
-    private boolean isTransportValid(IBackupTransport transport) {
-        if (mTransportBoundListener == null) {
-            Slog.w(TAG, "setTransportBoundListener() not called, assuming transport invalid");
-            return false;
-        }
-        return mTransportBoundListener.onTransportBound(transport);
-    }
-
-    private class TransportConnection implements ServiceConnection {
-
-        // Hold mTransportLock to access these fields so as to provide a consistent view of them.
-        private volatile IBackupTransport mBinder;
-        private volatile String mTransportName;
-
-        private final ComponentName mTransportComponent;
-
-        private TransportConnection(ComponentName transportComponent) {
-            mTransportComponent = transportComponent;
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName component, IBinder binder) {
-            synchronized (mTransportLock) {
-                mBinder = IBackupTransport.Stub.asInterface(binder);
-                boolean success = false;
-
-                EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE,
-                        component.flattenToShortString(), 1);
-
-                try {
-                    mTransportName = mBinder.name();
-                    // BackupManager requests some fields from the transport. If they are
-                    // invalid, throw away this transport.
-                    if (isTransportValid(mBinder)) {
-                        // We're now using the always-bound connection to do the registration but
-                        // when we remove the always-bound code this will be in the first binding
-                        // TODO: Move registration to first binding
-                        registerTransport(component, mBinder);
-                        // If registerTransport() hasn't thrown...
-                        success = true;
-                    }
-                } catch (RemoteException e) {
-                    success = false;
-                    Slog.e(TAG, "Couldn't get transport name.", e);
-                } finally {
-                    // we need to intern() the String of the component, so that we can use it with
-                    // Handler's removeMessages(), which uses == operator to compare the tokens
-                    String componentShortString = component.flattenToShortString().intern();
-                    if (success) {
-                        Slog.d(TAG, "Bound to transport: " + componentShortString);
-                        mBoundTransports.put(mTransportName, component);
-                        // cancel rebinding on timeout for this component as we've already connected
-                        mHandler.removeMessages(REBINDING_TIMEOUT_MSG, componentShortString);
-                    } else {
-                        Slog.w(TAG, "Bound to transport " + componentShortString +
-                                " but it is invalid");
-                        EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE,
-                                componentShortString, 0);
-                        mContext.unbindService(this);
-                        mValidTransports.remove(component);
-                        mEligibleTransports.remove(component);
-                        mBinder = null;
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName component) {
-            synchronized (mTransportLock) {
-                mBinder = null;
-                mBoundTransports.remove(mTransportName);
-            }
-            String componentShortString = component.flattenToShortString();
-            EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, componentShortString, 0);
-            Slog.w(TAG, "Disconnected from transport " + componentShortString);
-            scheduleRebindTimeout(component);
-        }
-
-        /**
-         * We'll attempt to explicitly rebind to a transport if it hasn't happened automatically
-         * for a few minutes after the binding went away.
-         */
-        private void scheduleRebindTimeout(ComponentName component) {
-            // we need to intern() the String of the component, so that we can use it with Handler's
-            // removeMessages(), which uses == operator to compare the tokens
-            final String componentShortString = component.flattenToShortString().intern();
-            final long rebindTimeout = getRebindTimeout();
-            mHandler.removeMessages(REBINDING_TIMEOUT_MSG, componentShortString);
-            Message msg = mHandler.obtainMessage(REBINDING_TIMEOUT_MSG);
-            msg.obj = componentShortString;
-            mHandler.sendMessageDelayed(msg, rebindTimeout);
-            Slog.d(TAG, "Scheduled explicit rebinding for " + componentShortString + " in "
-                    + rebindTimeout + "ms");
-        }
-
-        // Intentionally not synchronized -- the variable is volatile and changes to its value
-        // are inside synchronized blocks, providing a memory sync barrier; and this method
-        // does not touch any other state protected by that lock.
-        private IBackupTransport getBinder() {
-            return mBinder;
-        }
-
-        // Intentionally not synchronized; same as getBinder()
-        private String getName() {
-            return mTransportName;
-        }
-
-        // Intentionally not synchronized; same as getBinder()
-        private void bindIfUnbound() {
-            if (mBinder == null) {
-                Slog.d(TAG,
-                        "Rebinding to transport " + mTransportComponent.flattenToShortString());
-                bindToTransport(mTransportComponent, this);
-            }
-        }
-
-        private long getRebindTimeout() {
-            final boolean isDeviceProvisioned = Settings.Global.getInt(
-                    mContext.getContentResolver(),
-                    Settings.Global.DEVICE_PROVISIONED, 0) != 0;
-            return isDeviceProvisioned
-                    ? REBINDING_TIMEOUT_PROVISIONED_MS
-                    : REBINDING_TIMEOUT_UNPROVISIONED_MS;
-        }
-    }
-
-    public interface TransportBoundListener {
-        /** Should return true if this is a valid transport. */
-        boolean onTransportBound(IBackupTransport binder);
-    }
-
-    private class RebindOnTimeoutHandler extends Handler {
-
-        RebindOnTimeoutHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == REBINDING_TIMEOUT_MSG) {
-                String componentShortString = (String) msg.obj;
-                ComponentName transportComponent =
-                        ComponentName.unflattenFromString(componentShortString);
-                synchronized (mTransportLock) {
-                    if (mBoundTransports.containsValue(transportComponent)) {
-                        Slog.d(TAG, "Explicit rebinding timeout passed, but already bound to "
-                                + componentShortString + " so not attempting to rebind");
-                        return;
-                    }
-                    Slog.d(TAG, "Explicit rebinding timeout passed, attempting rebinding to: "
-                            + componentShortString);
-                    // unbind the existing (broken) connection
-                    TransportConnection conn = mValidTransports.get(transportComponent);
-                    if (conn != null) {
-                        mContext.unbindService(conn);
-                        Slog.d(TAG, "Unbinding the existing (broken) connection to transport: "
-                                + componentShortString);
-                    }
-                }
-                // rebind to transport
-                tryBindTransport(transportComponent);
-            } else {
-                Slog.e(TAG, "Unknown message sent to RebindOnTimeoutHandler, msg.what: "
-                        + msg.what);
-            }
-        }
-    }
-
-    private static void log_verbose(String message) {
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Slog.v(TAG, message);
-        }
-    }
-
-    // These only exists to make it testable with Robolectric, which is not updated to API level 24
-    // yet.
-    // TODO: Get rid of this once Robolectric is updated.
-    private static ComponentName getComponentName(ServiceInfo serviceInfo) {
-        return new ComponentName(serviceInfo.packageName, serviceInfo.name);
-    }
-
-    // These only exists to make it testable with Robolectric, which is not updated to API level 24
-    // yet.
-    // TODO: Get rid of this once Robolectric is updated.
-    public static UserHandle createSystemUserHandle() {
-        return new UserHandle(UserHandle.USER_SYSTEM);
+    private static Predicate<ComponentName> fromPackageFilter(String packageName) {
+        return transportComponent -> packageName.equals(transportComponent.getPackageName());
     }
 
     private static class TransportDescription {
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index c232241..cc3af8c 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -907,7 +907,15 @@
                         backupData = ParcelFileDescriptor.open(mBackupDataName,
                                 ParcelFileDescriptor.MODE_READ_ONLY);
                         backupManagerService.addBackupTrace("sending data to transport");
-                        int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
+
+                        int userInitiatedFlag =
+                                mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
+                        int incrementalFlag =
+                                mSavedStateName.length() == 0
+                                    ? BackupTransport.FLAG_NON_INCREMENTAL
+                                    : BackupTransport.FLAG_INCREMENTAL;
+                        int flags = userInitiatedFlag | incrementalFlag;
+
                         mStatus = transport.performBackup(mCurrentPackage, backupData, flags);
                     }
 
diff --git a/services/backup/java/com/android/server/backup/transport/OnTransportRegisteredListener.java b/services/backup/java/com/android/server/backup/transport/OnTransportRegisteredListener.java
new file mode 100644
index 0000000..391ec2d
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/transport/OnTransportRegisteredListener.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.transport;
+
+import com.android.server.backup.TransportManager;
+
+/**
+ * Listener called when a transport is registered with the {@link TransportManager}. Can be set
+ * using {@link TransportManager#setOnTransportRegisteredListener(OnTransportRegisteredListener)}.
+ */
+@FunctionalInterface
+public interface OnTransportRegisteredListener {
+    /**
+     * Called when a transport is successfully registered.
+     * @param transportName The name of the transport.
+     * @param transportDirName The dir name of the transport.
+     */
+    public void onTransportRegistered(String transportName, String transportDirName);
+}
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java
index 7bd9111..bd4a0bb 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java
@@ -236,7 +236,7 @@
                                     mBindIntent,
                                     mConnection,
                                     Context.BIND_AUTO_CREATE,
-                                    TransportManager.createSystemUserHandle());
+                                    UserHandle.SYSTEM);
                     if (hasBound) {
                         // We don't need to set a time-out because we are guaranteed to get a call
                         // back in ServiceConnection, either an onServiceConnected() or
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index a024d5a..15c0f3c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -89,10 +89,10 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.LocalLog;
 import com.android.server.ForceAppStandbyTracker.Listener;
-import com.android.server.LocalServices;
 
 /**
  * Alarm manager implementaion.
@@ -152,6 +152,8 @@
     private long mLastTickSet;
     private long mLastTickIssued; // elapsed
     private long mLastTickReceived;
+    private long mLastTickAdded;
+    private long mLastTickRemoved;
     int mBroadcastRefCount = 0;
     PowerManager.WakeLock mWakeLock;
     boolean mLastWakeLockUnimportantForLogging;
@@ -431,6 +433,9 @@
             end = seed.maxWhenElapsed;
             flags = seed.flags;
             alarms.add(seed);
+            if (seed.operation == mTimeTickSender) {
+                mLastTickAdded = System.currentTimeMillis();
+            }
         }
 
         int size() {
@@ -453,6 +458,9 @@
                 index = 0 - index - 1;
             }
             alarms.add(index, alarm);
+            if (alarm.operation == mTimeTickSender) {
+                mLastTickAdded = System.currentTimeMillis();
+            }
             if (DEBUG_BATCH) {
                 Slog.v(TAG, "Adding " + alarm + " to " + this);
             }
@@ -484,6 +492,9 @@
                     if (alarm.alarmClock != null) {
                         mNextAlarmClockMayChange = true;
                     }
+                    if (alarm.operation == mTimeTickSender) {
+                        mLastTickRemoved = System.currentTimeMillis();
+                    }
                 } else {
                     if (alarm.whenElapsed > newStart) {
                         newStart = alarm.whenElapsed;
@@ -700,6 +711,39 @@
         }
         return -1;
     }
+    /** @return total count of the alarms in a set of alarm batches. */
+    static int getAlarmCount(ArrayList<Batch> batches) {
+        int ret = 0;
+
+        final int size = batches.size();
+        for (int i = 0; i < size; i++) {
+            ret += batches.get(i).size();
+        }
+        return ret;
+    }
+
+    boolean haveAlarmsTimeTickAlarm(ArrayList<Alarm> alarms) {
+        if (alarms.size() == 0) {
+            return false;
+        }
+        final int batchSize = alarms.size();
+        for (int j = 0; j < batchSize; j++) {
+            if (alarms.get(j).operation == mTimeTickSender) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean haveBatchesTimeTickAlarm(ArrayList<Batch> batches) {
+        final int numBatches = batches.size();
+        for (int i = 0; i < numBatches; i++) {
+            if (haveAlarmsTimeTickAlarm(batches.get(i).alarms)) {
+                return true;
+            }
+        }
+        return false;
+    }
 
     // The RTC clock has moved arbitrarily, so we need to recalculate all the batching
     void rebatchAllAlarms() {
@@ -709,6 +753,11 @@
     }
 
     void rebatchAllAlarmsLocked(boolean doValidate) {
+        final int oldCount =
+                getAlarmCount(mAlarmBatches) + ArrayUtils.size(mPendingWhileIdleAlarms);
+        final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches)
+                || haveAlarmsTimeTickAlarm(mPendingWhileIdleAlarms);
+
         ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
         mAlarmBatches.clear();
         Alarm oldPendingIdleUntil = mPendingIdleUntil;
@@ -729,6 +778,18 @@
                 restorePendingWhileIdleAlarmsLocked();
             }
         }
+        final int newCount =
+                getAlarmCount(mAlarmBatches) + ArrayUtils.size(mPendingWhileIdleAlarms);
+        final boolean newHasTick = haveBatchesTimeTickAlarm(mAlarmBatches)
+                || haveAlarmsTimeTickAlarm(mPendingWhileIdleAlarms);
+
+        if (oldCount != newCount) {
+            Slog.wtf(TAG, "Rebatching: total count changed from " + oldCount + " to " + newCount);
+        }
+        if (oldHasTick != newHasTick) {
+            Slog.wtf(TAG, "Rebatching: hasTick changed from " + oldHasTick + " to " + newHasTick);
+        }
+
         rescheduleKernelAlarmsLocked();
         updateNextAlarmClockLocked();
     }
@@ -1162,12 +1223,12 @@
             // ignored; both services live in system_server
         }
         publishBinderService(Context.ALARM_SERVICE, mService);
-        mForceAppStandbyTracker.start();
     }
 
     @Override
     public void onBootPhase(int phase) {
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
+            mForceAppStandbyTracker.start();
             mConstants.start(getContext().getContentResolver());
             mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
             mLocalDeviceIdleController
@@ -1603,7 +1664,7 @@
 
             final long nowRTC = System.currentTimeMillis();
             final long nowELAPSED = SystemClock.elapsedRealtime();
-            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
 
             pw.print("  nowRTC="); pw.print(nowRTC);
             pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
@@ -1613,10 +1674,11 @@
             pw.print("="); pw.println(sdf.format(new Date(mLastTimeChangeClockTime)));
             pw.print("  mLastTimeChangeRealtime="); pw.println(mLastTimeChangeRealtime);
             pw.print("  mLastTickIssued=");
-            TimeUtils.formatDuration(mLastTickIssued - nowELAPSED, pw);
-            pw.println();
+            pw.println(sdf.format(new Date(nowRTC - (nowELAPSED - mLastTickIssued))));
             pw.print("  mLastTickReceived="); pw.println(sdf.format(new Date(mLastTickReceived)));
             pw.print("  mLastTickSet="); pw.println(sdf.format(new Date(mLastTickSet)));
+            pw.print("  mLastTickAdded="); pw.println(sdf.format(new Date(mLastTickAdded)));
+            pw.print("  mLastTickRemoved="); pw.println(sdf.format(new Date(mLastTickRemoved)));
             pw.println();
             if (!mInteractive) {
                 pw.print("  Time since non-interactive: ");
@@ -2400,6 +2462,10 @@
     }
 
     void removeLocked(final int uid) {
+        if (uid == Process.SYSTEM_UID) {
+            Slog.wtf(TAG, "removeLocked: Shouldn't for UID=" + uid);
+            return;
+        }
         boolean didRemove = false;
         final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid;
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
@@ -2448,6 +2514,7 @@
 
         boolean didRemove = false;
         final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(packageName);
+        final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches);
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
             didRemove |= b.remove(whichAlarms);
@@ -2455,6 +2522,11 @@
                 mAlarmBatches.remove(i);
             }
         }
+        final boolean newHasTick = haveBatchesTimeTickAlarm(mAlarmBatches);
+        if (oldHasTick != newHasTick) {
+            Slog.wtf(TAG, "removeLocked: hasTick changed from " + oldHasTick + " to " + newHasTick);
+        }
+
         for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
             final Alarm a = mPendingWhileIdleAlarms.get(i);
             if (a.matches(packageName)) {
@@ -2484,6 +2556,10 @@
     }
 
     void removeForStoppedLocked(final int uid) {
+        if (uid == Process.SYSTEM_UID) {
+            Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid);
+            return;
+        }
         boolean didRemove = false;
         final Predicate<Alarm> whichAlarms = (Alarm a) -> {
             try {
@@ -2524,6 +2600,10 @@
     }
 
     void removeUserLocked(int userHandle) {
+        if (userHandle == UserHandle.USER_SYSTEM) {
+            Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for user=" + userHandle);
+            return;
+        }
         boolean didRemove = false;
         final Predicate<Alarm> whichAlarms =
                 (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle;
@@ -3688,6 +3768,9 @@
                                     mDeliveryTracker, mHandler, null,
                                     allowWhileIdle ? mIdleOptions : null);
                 } catch (PendingIntent.CanceledException e) {
+                    if (alarm.operation == mTimeTickSender) {
+                        Slog.wtf(TAG, "mTimeTickSender canceled");
+                    }
                     if (alarm.repeatInterval > 0) {
                         // This IntentSender is no longer valid, but this
                         // is a repeating alarm, so toss it
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 86b0164..77521df 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -130,6 +130,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.DataConnectionStats;
+import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.KeepaliveTracker;
 import com.android.server.connectivity.LingerMonitor;
@@ -225,7 +226,11 @@
     @GuardedBy("mVpns")
     private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>();
 
+    // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
+    // a direct call to LockdownVpnTracker.isEnabled().
+    @GuardedBy("mVpns")
     private boolean mLockdownEnabled;
+    @GuardedBy("mVpns")
     private LockdownVpnTracker mLockdownTracker;
 
     final private Context mContext;
@@ -233,8 +238,6 @@
     // 0 is full bad, 100 is full good
     private int mDefaultInetConditionPublished = 0;
 
-    private int mNumDnsEntries;
-
     private boolean mTestMode;
     private static ConnectivityService sServiceInstance;
 
@@ -408,6 +411,7 @@
     final private InternalHandler mHandler;
     /** Handler used for incoming {@link NetworkStateTracker} events. */
     final private NetworkStateTrackerHandler mTrackerHandler;
+    private final DnsManager mDnsManager;
 
     private boolean mSystemReady;
     private Intent mInitialBroadcast;
@@ -880,6 +884,8 @@
         mMultinetworkPolicyTracker = createMultinetworkPolicyTracker(
                 mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
         mMultinetworkPolicyTracker.start();
+
+        mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties);
     }
 
     private Tethering makeTethering() {
@@ -995,9 +1001,9 @@
     }
 
     private Network[] getVpnUnderlyingNetworks(int uid) {
-        if (!mLockdownEnabled) {
-            int user = UserHandle.getUserId(uid);
-            synchronized (mVpns) {
+        synchronized (mVpns) {
+            if (!mLockdownEnabled) {
+                int user = UserHandle.getUserId(uid);
                 Vpn vpn = mVpns.get(user);
                 if (vpn != null && vpn.appliesToUid(uid)) {
                     return vpn.getUnderlyingNetworks();
@@ -1085,8 +1091,10 @@
         if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) {
             state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
         }
-        if (mLockdownTracker != null) {
-            mLockdownTracker.augmentNetworkInfo(state.networkInfo);
+        synchronized (mVpns) {
+            if (mLockdownTracker != null) {
+                mLockdownTracker.augmentNetworkInfo(state.networkInfo);
+            }
         }
     }
 
@@ -1251,8 +1259,8 @@
             result.put(nai.network, nc);
         }
 
-        if (!mLockdownEnabled) {
-            synchronized (mVpns) {
+        synchronized (mVpns) {
+            if (!mLockdownEnabled) {
                 Vpn vpn = mVpns.get(userId);
                 if (vpn != null) {
                     Network[] networks = vpn.getUnderlyingNetworks();
@@ -1578,9 +1586,11 @@
     }
 
     private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
-        if (mLockdownTracker != null) {
-            info = new NetworkInfo(info);
-            mLockdownTracker.augmentNetworkInfo(info);
+        synchronized (mVpns) {
+            if (mLockdownTracker != null) {
+                info = new NetworkInfo(info);
+                mLockdownTracker.augmentNetworkInfo(info);
+            }
         }
 
         Intent intent = new Intent(bcastType);
@@ -1826,24 +1836,6 @@
         }
     }
 
-    private void flushVmDnsCache() {
-        /*
-         * Tell the VMs to toss their DNS caches
-         */
-        Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        /*
-         * Connectivity events can happen before boot has completed ...
-         */
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     @Override
     public int getRestoreDefaultNetworkDelay(int networkType) {
         String restoreDefaultNetworkDelayStr = mSystemProperties.get(
@@ -2516,6 +2508,7 @@
     private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
         nri.unlinkDeathRecipient();
         mNetworkRequests.remove(nri.request);
+
         synchronized (mUidToNetworkRequestCount) {
             int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
             if (requests < 1) {
@@ -2528,6 +2521,7 @@
                 mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
             }
         }
+
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
         if (nri.request.isRequest()) {
             boolean wasKept = false;
@@ -3450,9 +3444,9 @@
     public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
             int userId) {
         enforceCrossUserPermission(userId);
-        throwIfLockdownEnabled();
 
         synchronized (mVpns) {
+            throwIfLockdownEnabled();
             Vpn vpn = mVpns.get(userId);
             if (vpn != null) {
                 return vpn.prepare(oldPackage, newPackage);
@@ -3496,9 +3490,9 @@
      */
     @Override
     public ParcelFileDescriptor establishVpn(VpnConfig config) {
-        throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mVpns) {
+            throwIfLockdownEnabled();
             return mVpns.get(user).establish(config);
         }
     }
@@ -3509,13 +3503,13 @@
      */
     @Override
     public void startLegacyVpn(VpnProfile profile) {
-        throwIfLockdownEnabled();
+        int user = UserHandle.getUserId(Binder.getCallingUid());
         final LinkProperties egress = getActiveLinkProperties();
         if (egress == null) {
             throw new IllegalStateException("Missing active network connection");
         }
-        int user = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mVpns) {
+            throwIfLockdownEnabled();
             mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
         }
     }
@@ -3541,11 +3535,11 @@
     @Override
     public VpnInfo[] getAllVpnInfo() {
         enforceConnectivityInternalPermission();
-        if (mLockdownEnabled) {
-            return new VpnInfo[0];
-        }
-
         synchronized (mVpns) {
+            if (mLockdownEnabled) {
+                return new VpnInfo[0];
+            }
+
             List<VpnInfo> infoList = new ArrayList<>();
             for (int i = 0; i < mVpns.size(); i++) {
                 VpnInfo info = createVpnInfo(mVpns.valueAt(i));
@@ -3610,33 +3604,33 @@
             return false;
         }
 
-        // Tear down existing lockdown if profile was removed
-        mLockdownEnabled = LockdownVpnTracker.isEnabled();
-        if (mLockdownEnabled) {
-            byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
-            if (profileTag == null) {
-                Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore");
-                return false;
-            }
-            String profileName = new String(profileTag);
-            final VpnProfile profile = VpnProfile.decode(
-                    profileName, mKeyStore.get(Credentials.VPN + profileName));
-            if (profile == null) {
-                Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName);
-                setLockdownTracker(null);
-                return true;
-            }
-            int user = UserHandle.getUserId(Binder.getCallingUid());
-            synchronized (mVpns) {
+        synchronized (mVpns) {
+            // Tear down existing lockdown if profile was removed
+            mLockdownEnabled = LockdownVpnTracker.isEnabled();
+            if (mLockdownEnabled) {
+                byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
+                if (profileTag == null) {
+                    Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore");
+                    return false;
+                }
+                String profileName = new String(profileTag);
+                final VpnProfile profile = VpnProfile.decode(
+                        profileName, mKeyStore.get(Credentials.VPN + profileName));
+                if (profile == null) {
+                    Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName);
+                    setLockdownTracker(null);
+                    return true;
+                }
+                int user = UserHandle.getUserId(Binder.getCallingUid());
                 Vpn vpn = mVpns.get(user);
                 if (vpn == null) {
                     Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
                     return false;
                 }
                 setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, vpn, profile));
+            } else {
+                setLockdownTracker(null);
             }
-        } else {
-            setLockdownTracker(null);
         }
 
         return true;
@@ -3646,6 +3640,7 @@
      * Internally set new {@link LockdownVpnTracker}, shutting down any existing
      * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
      */
+    @GuardedBy("mVpns")
     private void setLockdownTracker(LockdownVpnTracker tracker) {
         // Shutdown any existing tracker
         final LockdownVpnTracker existing = mLockdownTracker;
@@ -3660,6 +3655,7 @@
         }
     }
 
+    @GuardedBy("mVpns")
     private void throwIfLockdownEnabled() {
         if (mLockdownEnabled) {
             throw new IllegalStateException("Unavailable in lockdown mode");
@@ -3707,12 +3703,12 @@
         enforceConnectivityInternalPermission();
         enforceCrossUserPermission(userId);
 
-        // Can't set always-on VPN if legacy VPN is already in lockdown mode.
-        if (LockdownVpnTracker.isEnabled()) {
-            return false;
-        }
-
         synchronized (mVpns) {
+            // Can't set always-on VPN if legacy VPN is already in lockdown mode.
+            if (LockdownVpnTracker.isEnabled()) {
+                return false;
+            }
+
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
                 Slog.w(TAG, "User " + userId + " has no Vpn configuration");
@@ -3888,9 +3884,9 @@
             }
             userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
             mVpns.put(userId, userVpn);
-        }
-        if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
-            updateLockdownVpn();
+            if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+                updateLockdownVpn();
+            }
         }
     }
 
@@ -3927,11 +3923,13 @@
     }
 
     private void onUserUnlocked(int userId) {
-        // User present may be sent because of an unlock, which might mean an unlocked keystore.
-        if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
-            updateLockdownVpn();
-        } else {
-            startAlwaysOnVpn(userId);
+        synchronized (mVpns) {
+            // User present may be sent because of an unlock, which might mean an unlocked keystore.
+            if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+                updateLockdownVpn();
+            } else {
+                startAlwaysOnVpn(userId);
+            }
         }
     }
 
@@ -4586,41 +4584,17 @@
             return;  // no updating necessary
         }
 
+        final NetworkAgentInfo defaultNai = getDefaultNetwork();
+        final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId);
+
         Collection<InetAddress> dnses = newLp.getDnsServers();
         if (DBG) log("Setting DNS servers for network " + netId + " to " + dnses);
         try {
-            mNetd.setDnsConfigurationForNetwork(
-                    netId, NetworkUtils.makeStrings(dnses), newLp.getDomains());
+            mDnsManager.setDnsConfigurationForNetwork(
+                    netId, dnses, newLp.getDomains(), isDefaultNetwork);
         } catch (Exception e) {
             loge("Exception in setDnsConfigurationForNetwork: " + e);
         }
-        final NetworkAgentInfo defaultNai = getDefaultNetwork();
-        if (defaultNai != null && defaultNai.network.netId == netId) {
-            setDefaultDnsSystemProperties(dnses);
-        }
-        flushVmDnsCache();
-    }
-
-    private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
-        int last = 0;
-        for (InetAddress dns : dnses) {
-            ++last;
-            setNetDnsProperty(last, dns.getHostAddress());
-        }
-        for (int i = last + 1; i <= mNumDnsEntries; ++i) {
-            setNetDnsProperty(i, "");
-        }
-        mNumDnsEntries = last;
-    }
-
-    private void setNetDnsProperty(int which, String value) {
-        final String key = "net.dns" + which;
-        // Log and forget errors setting unsupported properties.
-        try {
-            mSystemProperties.set(key, value);
-        } catch (Exception e) {
-            Log.e(TAG, "Error setting unsupported net.dns property: ", e);
-        }
     }
 
     private String getNetworkPermission(NetworkCapabilities nc) {
@@ -4635,51 +4609,67 @@
     }
 
     /**
-     * Update the NetworkCapabilities for {@code networkAgent} to {@code networkCapabilities}
-     * augmented with any stateful capabilities implied from {@code networkAgent}
-     * (e.g., validated status and captive portal status).
-     *
-     * @param oldScore score of the network before any of the changes that prompted us
-     *                 to call this function.
-     * @param nai the network having its capabilities updated.
-     * @param networkCapabilities the new network capabilities.
+     * Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are
+     * maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
+     * and foreground status).
      */
-    private void updateCapabilities(
-            int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
+    private NetworkCapabilities mixInCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
         // Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
-        if (nai.everConnected && !nai.networkCapabilities.satisfiedByImmutableNetworkCapabilities(
-                networkCapabilities)) {
-            // TODO: consider not complaining when a network agent degrade its capabilities if this
+        if (nai.everConnected &&
+                !nai.networkCapabilities.satisfiedByImmutableNetworkCapabilities(nc)) {
+            // TODO: consider not complaining when a network agent degrades its capabilities if this
             // does not cause any request (that is not a listen) currently matching that agent to
             // stop being matched by the updated agent.
-            String diff = nai.networkCapabilities.describeImmutableDifferences(networkCapabilities);
+            String diff = nai.networkCapabilities.describeImmutableDifferences(nc);
             if (!TextUtils.isEmpty(diff)) {
                 Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
             }
         }
 
         // Don't modify caller's NetworkCapabilities.
-        networkCapabilities = new NetworkCapabilities(networkCapabilities);
+        NetworkCapabilities newNc = new NetworkCapabilities(nc);
         if (nai.lastValidated) {
-            networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
+            newNc.addCapability(NET_CAPABILITY_VALIDATED);
         } else {
-            networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
+            newNc.removeCapability(NET_CAPABILITY_VALIDATED);
         }
         if (nai.lastCaptivePortalDetected) {
-            networkCapabilities.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
+            newNc.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
         } else {
-            networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
+            newNc.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
         }
         if (nai.isBackgroundNetwork()) {
-            networkCapabilities.removeCapability(NET_CAPABILITY_FOREGROUND);
+            newNc.removeCapability(NET_CAPABILITY_FOREGROUND);
         } else {
-            networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
+            newNc.addCapability(NET_CAPABILITY_FOREGROUND);
         }
 
-        if (Objects.equals(nai.networkCapabilities, networkCapabilities)) return;
+        return newNc;
+    }
+
+    /**
+     * Update the NetworkCapabilities for {@code nai} to {@code nc}. Specifically:
+     *
+     * 1. Calls mixInCapabilities to merge the passed-in NetworkCapabilities {@code nc} with the
+     *    capabilities we manage and store in {@code nai}, such as validated status and captive
+     *    portal status)
+     * 2. Takes action on the result: changes network permissions, sends CAP_CHANGED callbacks, and
+     *    potentially triggers rematches.
+     * 3. Directly informs other network stack components (NetworkStatsService, VPNs, etc. of the
+     *    change.)
+     *
+     * @param oldScore score of the network before any of the changes that prompted us
+     *                 to call this function.
+     * @param nai the network having its capabilities updated.
+     * @param nc the new network capabilities.
+     */
+    private void updateCapabilities(int oldScore, NetworkAgentInfo nai, NetworkCapabilities nc) {
+        NetworkCapabilities newNc = mixInCapabilities(nai, nc);
+
+        if (Objects.equals(nai.networkCapabilities, newNc)) return;
 
         final String oldPermission = getNetworkPermission(nai.networkCapabilities);
-        final String newPermission = getNetworkPermission(networkCapabilities);
+        final String newPermission = getNetworkPermission(newNc);
         if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
             try {
                 mNetd.setNetworkPermission(nai.network.netId, newPermission);
@@ -4691,11 +4681,10 @@
         final NetworkCapabilities prevNc;
         synchronized (nai) {
             prevNc = nai.networkCapabilities;
-            nai.networkCapabilities = networkCapabilities;
+            nai.networkCapabilities = newNc;
         }
 
-        if (nai.getCurrentScore() == oldScore &&
-                networkCapabilities.equalRequestableCapabilities(prevNc)) {
+        if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {
             // If the requestable capabilities haven't changed, and the score hasn't changed, then
             // the change we're processing can't affect any requests, it can only affect the listens
             // on this network. We might have been called by rematchNetworkAndRequests when a
@@ -4711,15 +4700,15 @@
         // Report changes that are interesting for network statistics tracking.
         if (prevNc != null) {
             final boolean meteredChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_METERED) !=
-                    networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED);
+                    newNc.hasCapability(NET_CAPABILITY_NOT_METERED);
             final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
-                    networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+                    newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
             if (meteredChanged || roamingChanged) {
                 notifyIfacesChangedForNetworkStats();
             }
         }
 
-        if (!networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+        if (!newNc.hasTransport(TRANSPORT_VPN)) {
             // Tell VPNs about updated capabilities, since they may need to
             // bubble those changes through.
             synchronized (mVpns) {
@@ -4893,7 +4882,7 @@
         notifyLockdownVpn(newNetwork);
         handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
         updateTcpBufferSizes(newNetwork);
-        setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+        mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
     }
 
     private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
@@ -5243,11 +5232,13 @@
     }
 
     private void notifyLockdownVpn(NetworkAgentInfo nai) {
-        if (mLockdownTracker != null) {
-            if (nai != null && nai.isVPN()) {
-                mLockdownTracker.onVpnStateChanged(nai.networkInfo);
-            } else {
-                mLockdownTracker.onNetworkInfoChanged();
+        synchronized (mVpns) {
+            if (mLockdownTracker != null) {
+                if (nai != null && nai.isVPN()) {
+                    mLockdownTracker.onVpnStateChanged(nai.networkInfo);
+                } else {
+                    mLockdownTracker.onNetworkInfoChanged();
+                }
             }
         }
     }
@@ -5477,28 +5468,28 @@
 
     @Override
     public boolean addVpnAddress(String address, int prefixLength) {
-        throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mVpns) {
+            throwIfLockdownEnabled();
             return mVpns.get(user).addAddress(address, prefixLength);
         }
     }
 
     @Override
     public boolean removeVpnAddress(String address, int prefixLength) {
-        throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mVpns) {
+            throwIfLockdownEnabled();
             return mVpns.get(user).removeAddress(address, prefixLength);
         }
     }
 
     @Override
     public boolean setUnderlyingNetworksForVpn(Network[] networks) {
-        throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
-        boolean success;
+        final boolean success;
         synchronized (mVpns) {
+            throwIfLockdownEnabled();
             success = mVpns.get(user).setUnderlyingNetworks(networks);
         }
         if (success) {
@@ -5558,31 +5549,31 @@
                     setAlwaysOnVpnPackage(userId, null, false);
                     setVpnPackageAuthorization(alwaysOnPackage, userId, false);
                 }
-            }
 
-            // Turn Always-on VPN off
-            if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    mKeyStore.delete(Credentials.LOCKDOWN_VPN);
-                    mLockdownEnabled = false;
-                    setLockdownTracker(null);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
+                // Turn Always-on VPN off
+                if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        mKeyStore.delete(Credentials.LOCKDOWN_VPN);
+                        mLockdownEnabled = false;
+                        setLockdownTracker(null);
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
                 }
-            }
 
-            // Turn VPN off
-            VpnConfig vpnConfig = getVpnConfig(userId);
-            if (vpnConfig != null) {
-                if (vpnConfig.legacy) {
-                    prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
-                } else {
-                    // Prevent this app (packagename = vpnConfig.user) from initiating VPN connections
-                    // in the future without user intervention.
-                    setVpnPackageAuthorization(vpnConfig.user, userId, false);
+                // Turn VPN off
+                VpnConfig vpnConfig = getVpnConfig(userId);
+                if (vpnConfig != null) {
+                    if (vpnConfig.legacy) {
+                        prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
+                    } else {
+                        // Prevent this app (packagename = vpnConfig.user) from initiating
+                        // VPN connections in the future without user intervention.
+                        setVpnPackageAuthorization(vpnConfig.user, userId, false);
 
-                    prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
+                        prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index 61d3833..8776f3a 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -33,8 +34,10 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.Pair;
+import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
 
@@ -59,15 +62,16 @@
  * - Global "force all apps standby" mode enforced by battery saver.
  *
  * TODO: In general, we can reduce the number of callbacks by checking all signals before sending
- *    each callback. For example, even when an UID comes into the foreground, if it wasn't
- *    originally restricted, then there's no need to send an event.
- *    Doing this would be error-prone, so we punt it for now, but we should revisit it later.
+ * each callback. For example, even when an UID comes into the foreground, if it wasn't
+ * originally restricted, then there's no need to send an event.
+ * Doing this would be error-prone, so we punt it for now, but we should revisit it later.
  *
  * Test:
-   atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+ * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
  */
 public class ForceAppStandbyTracker {
     private static final String TAG = "ForceAppStandbyTracker";
+    private static final boolean DEBUG = false;
 
     @GuardedBy("ForceAppStandbyTracker.class")
     private static ForceAppStandbyTracker sInstance;
@@ -107,7 +111,43 @@
     boolean mStarted;
 
     @GuardedBy("mLock")
-    boolean mForceAllAppsStandby;
+    boolean mForceAllAppsStandby;   // True if device is in extreme battery saver mode
+
+    @GuardedBy("mLock")
+    boolean mForcedAppStandbyEnabled;   // True if the forced app standby feature is enabled
+
+    private class FeatureFlagObserver extends ContentObserver {
+        FeatureFlagObserver() {
+            super(null);
+        }
+
+        void register() {
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED),
+                    false, this);
+        }
+
+        boolean isForcedAppStandbyEnabled() {
+            return Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            final boolean enabled = isForcedAppStandbyEnabled();
+            synchronized (mLock) {
+                if (mForcedAppStandbyEnabled == enabled) {
+                    return;
+                }
+                mForcedAppStandbyEnabled = enabled;
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled);
+                }
+            }
+            mHandler.notifyFeatureFlagChanged();
+        }
+    }
 
     public static abstract class Listener {
         /**
@@ -246,6 +286,9 @@
             mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
             mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
             mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
+            final FeatureFlagObserver flagObserver = new FeatureFlagObserver();
+            flagObserver.register();
+            mForcedAppStandbyEnabled = flagObserver.isForcedAppStandbyEnabled();
 
             try {
                 mIActivityManager.registerUidObserver(new UidObserver(),
@@ -364,7 +407,7 @@
      */
     boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
             boolean restricted) {
-        final int index =  findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
+        final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
         final boolean wasRestricted = index >= 0;
         if (wasRestricted == restricted) {
             return false;
@@ -418,25 +461,30 @@
     }
 
     private final class UidObserver extends IUidObserver.Stub {
-        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        @Override
+        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
         }
 
-        @Override public void onUidGone(int uid, boolean disabled) {
+        @Override
+        public void onUidGone(int uid, boolean disabled) {
             uidToBackground(uid, /*remove=*/ true);
         }
 
-        @Override public void onUidActive(int uid) {
+        @Override
+        public void onUidActive(int uid) {
             uidToForeground(uid);
         }
 
-        @Override public void onUidIdle(int uid, boolean disabled) {
+        @Override
+        public void onUidIdle(int uid, boolean disabled) {
             // Just to avoid excessive memcpy, don't remove from the array in this case.
             uidToBackground(uid, /*remove=*/ false);
         }
 
-        @Override public void onUidCachedChanged(int uid, boolean cached) {
+        @Override
+        public void onUidCachedChanged(int uid, boolean cached) {
         }
-    };
+    }
 
     private final class AppOpsWatcher extends IAppOpsCallback.Stub {
         @Override
@@ -481,8 +529,8 @@
         private static final int MSG_ALL_WHITELIST_CHANGED = 4;
         private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
         private static final int MSG_FORCE_ALL_CHANGED = 6;
-
         private static final int MSG_USER_REMOVED = 7;
+        private static final int MSG_FEATURE_FLAG_CHANGED = 8;
 
         public MyHandler(Looper looper) {
             super(looper);
@@ -491,6 +539,7 @@
         public void notifyUidForegroundStateChanged(int uid) {
             obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget();
         }
+
         public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
             obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
         }
@@ -511,12 +560,16 @@
             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
         }
 
+        public void notifyFeatureFlagChanged() {
+            obtainMessage(MSG_FEATURE_FLAG_CHANGED).sendToTarget();
+        }
+
         public void doUserRemoved(int userId) {
             obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
         }
 
         @Override
-        public void dispatchMessage(Message msg) {
+        public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_USER_REMOVED:
                     handleUserRemoved(msg.arg1);
@@ -562,6 +615,19 @@
                         l.onForceAllAppsStandbyChanged(sender);
                     }
                     return;
+                case MSG_FEATURE_FLAG_CHANGED:
+                    // Feature flag for forced app standby changed.
+                    final boolean unblockAlarms;
+                    synchronized (mLock) {
+                        unblockAlarms = !mForcedAppStandbyEnabled && !mForceAllAppsStandby;
+                    }
+                    for (Listener l: cloneListeners()) {
+                        l.updateAllJobs();
+                        if (unblockAlarms) {
+                            l.unblockAllUnrestrictedAlarms();
+                        }
+                    }
+                    return;
                 case MSG_USER_REMOVED:
                     handleUserRemoved(msg.arg1);
                     return;
@@ -701,7 +767,7 @@
                 return true;
             }
 
-            return isRunAnyRestrictedLocked(uid, packageName);
+            return mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName);
         }
     }
 
@@ -766,6 +832,9 @@
     public void dump(PrintWriter pw, String indent) {
         synchronized (mLock) {
             pw.print(indent);
+            pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);
+
+            pw.print(indent);
             pw.print("Force all apps standby: ");
             pw.println(isForceAllAppsStandbyEnabled());
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8a15ded..8f646e7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.Manifest.permission.SHUTDOWN;
 import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
@@ -209,12 +210,6 @@
         public static final int StrictCleartext           = 617;
     }
 
-    /* Defaults for resolver parameters. */
-    public static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
-    public static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
-    public static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
-    public static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
-
     /**
      * String indicating a softap command.
      */
@@ -1768,6 +1763,8 @@
 
     @Override
     public boolean setDataSaverModeEnabled(boolean enable) {
+        mContext.enforceCallingOrSelfPermission(NETWORK_SETTINGS, TAG);
+
         if (DBG) Log.d(TAG, "setDataSaverMode: " + enable);
         synchronized (mQuotaLock) {
             if (mDataSaverMode == enable) {
@@ -1947,66 +1944,14 @@
     }
 
     @Override
-    public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) {
+    public void setDnsConfigurationForNetwork(int netId, String[] servers, String[] domains,
+                    int[] params, boolean useTls, String tlsHostname) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final ContentResolver cr = mContext.getContentResolver();
-
-        int sampleValidity = Settings.Global.getInt(cr,
-                Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
-                DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
-        if (sampleValidity < 0 || sampleValidity > 65535) {
-            Slog.w(TAG, "Invalid sampleValidity=" + sampleValidity + ", using default=" +
-                    DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
-            sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
-        }
-
-        int successThreshold = Settings.Global.getInt(cr,
-                Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
-                DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
-        if (successThreshold < 0 || successThreshold > 100) {
-            Slog.w(TAG, "Invalid successThreshold=" + successThreshold + ", using default=" +
-                    DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
-            successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
-        }
-
-        int minSamples = Settings.Global.getInt(cr,
-                Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
-        int maxSamples = Settings.Global.getInt(cr,
-                Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
-        if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) {
-            Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples +
-                    "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
-                    DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
-            minSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
-            maxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
-        }
-
-        final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
-        final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
-        final boolean useTls = shouldUseTls(cr);
-        // TODO: Populate tlsHostname once it's decided how the hostname's IP
-        // addresses will be resolved:
-        //
-        //     [1] network-provided DNS servers are included here with the
-        //         hostname and netd will use the network-provided servers to
-        //         resolve the hostname and fix up its internal structures, or
-        //
-        //     [2] network-provided DNS servers are included here without the
-        //         hostname, the ConnectivityService layer resolves the given
-        //         hostname, and then reconfigures netd with this information.
-        //
-        // In practice, there will always be a need for ConnectivityService or
-        // the captive portal app to use the network-provided services to make
-        // some queries. This argues in favor of [1], in concert with another
-        // mechanism, perhaps setting a high bit in the netid, to indicate
-        // via existing DNS APIs which set of servers (network-provided or
-        // non-network-provided private DNS) should be queried.
-        final String tlsHostname = "";
         final String[] tlsFingerprints = new String[0];
         try {
-            mNetdService.setResolverConfiguration(netId, servers, domainStrs, params,
-                    useTls, tlsHostname, tlsFingerprints);
+            mNetdService.setResolverConfiguration(
+                    netId, servers, domains, params, useTls, tlsHostname, tlsFingerprints);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -2563,12 +2508,16 @@
 
     @Override
     public void removeNetwork(int netId) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
 
         try {
-            mConnector.execute("network", "destroy", netId);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkDestroy(netId);
+        } catch (ServiceSpecificException e) {
+            Log.w(TAG, "removeNetwork(" + netId + "): ", e);
+            throw e;
+        } catch (RemoteException e) {
+            Log.w(TAG, "removeNetwork(" + netId + "): ", e);
+            throw e.rethrowAsRuntimeException();
         }
     }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index dc2f2a5..7361e70 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -49,6 +49,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.ObbInfo;
+import android.database.ContentObserver;
 import android.net.TrafficStats;
 import android.net.Uri;
 import android.os.Binder;
@@ -170,6 +171,10 @@
     // Static direct instance pointer for the tightly-coupled idle service to use
     static StorageManagerService sSelf = null;
 
+    /* Read during boot to decide whether to enable zram when available */
+    private static final String ZRAM_ENABLED_PROPERTY =
+        "persist.sys.zram_enabled";
+
     public static class Lifecycle extends SystemService {
         private StorageManagerService mStorageManagerService;
 
@@ -733,6 +738,41 @@
 
         // Start scheduling nominally-daily fstrim operations
         MountServiceIdler.scheduleIdlePass(mContext);
+
+        // Toggle zram-enable system property in response to settings
+        mContext.getContentResolver().registerContentObserver(
+            Settings.Global.getUriFor(Settings.Global.ZRAM_ENABLED),
+            false /*notifyForDescendants*/,
+            new ContentObserver(null /* current thread */) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    refreshZramSettings();
+                }
+            });
+        refreshZramSettings();
+    }
+
+    /**
+     * Update the zram_enabled system property (which init reads to
+     * decide whether to enable zram) to reflect the zram_enabled
+     * preference (which we can change for experimentation purposes).
+     */
+    private void refreshZramSettings() {
+        String propertyValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
+        if ("".equals(propertyValue)) {
+            return;  // System doesn't have zram toggling support
+        }
+        String desiredPropertyValue =
+            Settings.Global.getInt(mContext.getContentResolver(),
+                                   Settings.Global.ZRAM_ENABLED,
+                                   1) != 0
+            ? "1" : "0";
+        if (!desiredPropertyValue.equals(propertyValue)) {
+            // Avoid redundant disk writes by setting only if we're
+            // changing the property value. There's no race: we're the
+            // sole writer.
+            SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 831c9cb..6747be3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -147,6 +147,8 @@
 
     private int[] mDataActivationState;
 
+    private boolean[] mUserMobileDataState;
+
     private SignalStrength[] mSignalStrength;
 
     private boolean[] mMessageWaiting;
@@ -304,6 +306,7 @@
         mServiceState = new ServiceState[numPhones];
         mVoiceActivationState = new int[numPhones];
         mDataActivationState = new int[numPhones];
+        mUserMobileDataState = new boolean[numPhones];
         mSignalStrength = new SignalStrength[numPhones];
         mMessageWaiting = new boolean[numPhones];
         mCallForwarding = new boolean[numPhones];
@@ -320,6 +323,7 @@
             mCallIncomingNumber[i] =  "";
             mServiceState[i] =  new ServiceState();
             mSignalStrength[i] =  new SignalStrength();
+            mUserMobileDataState[i] = false;
             mMessageWaiting[i] =  false;
             mCallForwarding[i] =  false;
             mCellLocation[i] = new Bundle();
@@ -656,6 +660,13 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
+                        try {
+                            r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                 }
             }
         } else {
@@ -1012,6 +1023,33 @@
         }
     }
 
+    public void notifyUserMobileDataStateChangedForPhoneId(int phoneId, int subId, boolean state) {
+        if (!checkNotifyPermission("notifyUserMobileDataStateChanged()")) {
+            return;
+        }
+        if (VDBG) {
+            log("notifyUserMobileDataStateChangedForSubscriberPhoneID: subId=" + phoneId
+                    + " state=" + state);
+        }
+        synchronized (mRecords) {
+            if (validatePhoneId(phoneId)) {
+                mMessageWaiting[phoneId] = state;
+                for (Record r : mRecords) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) &&
+                            idMatch(r.subId, subId, phoneId)) {
+                        try {
+                            r.callback.onUserMobileDataStateChanged(state);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     public void notifyCallForwardingChanged(boolean cfi) {
         notifyCallForwardingChangedForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cfi);
     }
@@ -1374,6 +1412,7 @@
                 pw.println("mServiceState=" + mServiceState[i]);
                 pw.println("mVoiceActivationState= " + mVoiceActivationState[i]);
                 pw.println("mDataActivationState= " + mDataActivationState[i]);
+                pw.println("mUserMobileDataState= " + mUserMobileDataState[i]);
                 pw.println("mSignalStrength=" + mSignalStrength[i]);
                 pw.println("mMessageWaiting=" + mMessageWaiting[i]);
                 pw.println("mCallForwarding=" + mCallForwarding[i]);
@@ -1755,6 +1794,18 @@
             }
         }
 
+        if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
+            try {
+                if (VDBG) {
+                    log("checkPossibleMissNotify: onUserMobileDataStateChanged phoneId="
+                            + phoneId + " umds=" + mUserMobileDataState[phoneId]);
+                }
+                r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
+            } catch (RemoteException ex) {
+                mRemoveList.add(r.binder);
+            }
+        }
+
         if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
             try {
                 if (VDBG) {
diff --git a/services/core/java/com/android/server/am/LaunchingActivityPositioner.java b/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
similarity index 68%
rename from services/core/java/com/android/server/am/LaunchingActivityPositioner.java
rename to services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
index 793884d..f44ee7a 100644
--- a/services/core/java/com/android/server/am/LaunchingActivityPositioner.java
+++ b/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
@@ -19,23 +19,25 @@
 import android.app.ActivityOptions;
 import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
-import com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner;
+
+import com.android.server.am.LaunchParamsController.LaunchParams;
+import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
 
 /**
- * An implementation of {@link LaunchingBoundsPositioner}, which applies the launch bounds specified
+ * An implementation of {@link LaunchParamsModifier}, which applies the launch bounds specified
  * inside {@link ActivityOptions#getLaunchBounds()}.
  */
-public class LaunchingActivityPositioner implements LaunchingBoundsPositioner {
+public class ActivityLaunchParamsModifier implements LaunchParamsModifier {
     private final ActivityStackSupervisor mSupervisor;
 
-    LaunchingActivityPositioner(ActivityStackSupervisor activityStackSupervisor) {
+    ActivityLaunchParamsModifier(ActivityStackSupervisor activityStackSupervisor) {
         mSupervisor = activityStackSupervisor;
     }
 
     @Override
-    public int onCalculateBounds(TaskRecord task, ActivityInfo.WindowLayout layout,
-            ActivityRecord activity, ActivityRecord source,
-            ActivityOptions options, Rect current, Rect result) {
+    public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+            ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+            LaunchParams currentParams, LaunchParams outParams) {
         // We only care about figuring out bounds for activities.
         if (activity == null) {
             return RESULT_SKIP;
@@ -43,7 +45,7 @@
 
         // Activity must be resizeable in the specified task.
         if (!(mSupervisor.canUseActivityOptionsLaunchBounds(options)
-            && (activity.isResizeable() || (task != null && task.isResizeable())))) {
+                && (activity.isResizeable() || (task != null && task.isResizeable())))) {
             return RESULT_SKIP;
         }
 
@@ -54,7 +56,7 @@
             return RESULT_SKIP;
         }
 
-        result.set(bounds);
+        outParams.mBounds.set(bounds);
 
         // When this is the most explicit position specification so we should not allow further
         // modification of the position.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 624035d..dfe89e0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -397,6 +397,7 @@
 import com.android.internal.os.TransferPipe;
 import com.android.internal.os.Zygote;
 import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.KeyguardDismissCallback;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
@@ -6242,7 +6243,7 @@
 
                     // Clear its pending alarms
                     AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class);
-                    ami.removeAlarmsForUid(uid);
+                    ami.removeAlarmsForUid(appInfo.uid);
                 }
             } catch (RemoteException e) {
             }
@@ -7260,15 +7261,22 @@
             }
 
             ProfilerInfo profilerInfo = null;
-            String agent = null;
+            String preBindAgent = null;
             if (mProfileApp != null && mProfileApp.equals(processName)) {
                 mProfileProc = app;
-                profilerInfo = (mProfilerInfo != null && mProfilerInfo.profileFile != null) ?
-                        new ProfilerInfo(mProfilerInfo) : null;
-                agent = mProfilerInfo != null ? mProfilerInfo.agent : null;
+                if (mProfilerInfo != null) {
+                    // Send a profiler info object to the app if either a file is given, or
+                    // an agent should be loaded at bind-time.
+                    boolean needsInfo = mProfilerInfo.profileFile != null
+                            || mProfilerInfo.attachAgentDuringBind;
+                    profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null;
+                    if (!mProfilerInfo.attachAgentDuringBind) {
+                        preBindAgent = mProfilerInfo.agent;
+                    }
+                }
             } else if (app.instr != null && app.instr.mProfileFile != null) {
                 profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
-                        null);
+                        null, false);
             }
 
             boolean enableTrackAllocation = false;
@@ -7337,8 +7345,8 @@
 
             // If we were asked to attach an agent on startup, do so now, before we're binding
             // application code.
-            if (agent != null) {
-                thread.attachAgent(agent);
+            if (preBindAgent != null) {
+                thread.attachAgent(preBindAgent);
             }
 
             checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
@@ -8386,22 +8394,12 @@
                     // entering picture-in-picture (this will prompt the user to authenticate if the
                     // device is currently locked).
                     try {
-                        dismissKeyguard(token, new IKeyguardDismissCallback.Stub() {
-                            @Override
-                            public void onDismissError() throws RemoteException {
-                                // Do nothing
-                            }
-
+                        dismissKeyguard(token, new KeyguardDismissCallback() {
                             @Override
                             public void onDismissSucceeded() throws RemoteException {
                                 mHandler.post(enterPipRunnable);
                             }
-
-                            @Override
-                            public void onDismissCancelled() throws RemoteException {
-                                // Do nothing
-                            }
-                        });
+                        }, null /* message */);
                     } catch (RemoteException e) {
                         // Local call
                     }
@@ -14175,7 +14173,7 @@
             for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
                 ProcessRecord proc = mLruProcesses.get(i);
                 if (proc.notCachedSinceIdle) {
-                    if (proc.setProcState >= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+                    if (proc.setProcState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
                             && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
                         if (doKilling && proc.initialIdlePss != 0
                                 && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
@@ -21420,7 +21418,7 @@
                 mAppWarnings.onDensityChanged();
 
                 killAllBackgroundProcessesExcept(N,
-                        ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+                        ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
             }
         }
 
@@ -22394,6 +22392,7 @@
             // to the top state.
             switch (procState) {
                 case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+                case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
                     // Something else is keeping it at this level, just leave it.
                     break;
                 case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
@@ -23231,7 +23230,7 @@
         // To avoid some abuse patterns, we are going to be careful about what we consider
         // to be an app interaction.  Being the top activity doesn't count while the display
         // is sleeping, nor do short foreground services.
-        if (app.curProcState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+        if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP) {
             isInteraction = true;
             app.fgInteractionTime = 0;
         } else if (app.curProcState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -24748,6 +24747,7 @@
                 ActivityManagerService.this.onUserStoppedLocked(userId);
             }
             mBatteryStatsService.onUserRemoved(userId);
+            mUserController.onUserRemoved(userId);
         }
 
         @Override
@@ -25128,6 +25128,11 @@
         public void registerScreenObserver(ScreenObserver observer) {
             mScreenObservers.add(observer);
         }
+
+        @Override
+        public boolean canStartMoreUsers() {
+            return mUserController.canStartMoreUsers();
+        }
     }
 
     /**
@@ -25275,11 +25280,15 @@
     }
 
     @Override
-    public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback)
-            throws RemoteException {
+    public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback,
+            CharSequence message) throws RemoteException {
+        if (message != null) {
+            enforceCallingPermission(permission.SHOW_KEYGUARD_MESSAGE,
+                    "dismissKeyguard()");
+        }
         final long callingId = Binder.clearCallingIdentity();
         try {
-            mKeyguardController.dismissKeyguard(token, callback);
+            mKeyguardController.dismissKeyguard(token, callback, message);
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
@@ -25334,6 +25343,10 @@
                 }
             }
         }
+        if (updateFrameworkRes && mWindowManager != null) {
+            ActivityThread.currentActivityThread().getExecutor().execute(
+                    mWindowManager::onOverlayChanged);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 4f60e17..1240f5e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -109,6 +109,7 @@
     private boolean mAutoStop;
     private boolean mStreaming;   // Streaming the profiling output to a file.
     private String mAgent;  // Agent to attach on startup.
+    private boolean mAttachAgentDuringBind;  // Whether agent should be attached late.
     private int mDisplayId;
     private int mWindowingMode;
     private int mActivityType;
@@ -296,7 +297,21 @@
                 } else if (opt.equals("--streaming")) {
                     mStreaming = true;
                 } else if (opt.equals("--attach-agent")) {
+                    if (mAgent != null) {
+                        cmd.getErrPrintWriter().println(
+                                "Multiple --attach-agent(-bind) not supported");
+                        return false;
+                    }
                     mAgent = getNextArgRequired();
+                    mAttachAgentDuringBind = false;
+                } else if (opt.equals("--attach-agent-bind")) {
+                    if (mAgent != null) {
+                        cmd.getErrPrintWriter().println(
+                                "Multiple --attach-agent(-bind) not supported");
+                        return false;
+                    }
+                    mAgent = getNextArgRequired();
+                    mAttachAgentDuringBind = true;
                 } else if (opt.equals("-R")) {
                     mRepeat = Integer.parseInt(getNextArgRequired());
                 } else if (opt.equals("-S")) {
@@ -384,7 +399,7 @@
                     }
                 }
                 profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop,
-                        mStreaming, mAgent);
+                        mStreaming, mAgent, mAttachAgentDuringBind);
             }
 
             pw.println("Starting: " + intent);
@@ -766,7 +781,7 @@
                 return -1;
             }
             profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming,
-                    null);
+                    null, false);
         }
 
         try {
@@ -2544,6 +2559,7 @@
             pw.println("          (use with --start-profiler)");
             pw.println("      -P <FILE>: like above, but profiling stops when app goes idle");
             pw.println("      --attach-agent <agent>: attach the given agent before binding");
+            pw.println("      --attach-agent-bind <agent>: attach the given agent during binding");
             pw.println("      -R: repeat the activity launch <COUNT> times.  Prior to each repeat,");
             pw.println("          the top activity will be finished.");
             pw.println("      -S: force stop the target app before starting the activity");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e1907d3..b5fbee6 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -135,6 +135,7 @@
 import android.app.servertransaction.MoveToDisplayItem;
 import android.app.servertransaction.MultiWindowModeChangeItem;
 import android.app.servertransaction.NewIntentItem;
+import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.PipModeChangeItem;
 import android.app.servertransaction.WindowVisibilityItem;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -1607,6 +1608,16 @@
             // The activity may be waiting for stop, but that is no longer appropriate for it.
             mStackSupervisor.mStoppingActivities.remove(this);
             mStackSupervisor.mGoingToSleepActivities.remove(this);
+
+            // If the activity is stopped or stopping, cycle to the paused state.
+            if (state == STOPPED || state == STOPPING) {
+                // An activity must be in the {@link PAUSING} state for the system to validate
+                // the move to {@link PAUSED}.
+                state = PAUSING;
+                service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+                        PauseActivityItem.obtain(finishing, false /* userLeaving */,
+                                configChangeFlags, false /* dontReport */));
+            }
         } catch (Exception e) {
             // Just skip on any failure; we'll make it visible when it next restarts.
             Slog.w(TAG, "Exception thrown making visibile: " + intent.getComponent(), e);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 831b31e..a343965 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -5052,7 +5052,7 @@
         addTask(task, toTop, "createTaskRecord");
         final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
                 .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
-        if (!mStackSupervisor.getLaunchingBoundsController()
+        if (!mStackSupervisor.getLaunchParamsController()
                 .layoutTask(task, info.windowLayout, activity, source, options)
                 && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
             task.updateOverrideConfiguration(getOverrideBounds());
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 21085fa..b567303 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -300,7 +300,7 @@
     WindowManagerService mWindowManager;
     DisplayManager mDisplayManager;
 
-    private LaunchingBoundsController mLaunchingBoundsController;
+    private LaunchParamsController mLaunchParamsController;
 
     /**
      * Maps the task identifier that activities are currently being started in to the userId of the
@@ -593,8 +593,8 @@
                 mHandler.getLooper());
         mKeyguardController = new KeyguardController(mService, this);
 
-        mLaunchingBoundsController = new LaunchingBoundsController();
-        mLaunchingBoundsController.registerDefaultPositioners(this);
+        mLaunchParamsController = new LaunchParamsController(mService);
+        mLaunchParamsController.registerDefaultModifiers(this);
     }
 
 
@@ -2220,8 +2220,8 @@
                 || mService.mSupportsFreeformWindowManagement;
     }
 
-    LaunchingBoundsController getLaunchingBoundsController() {
-        return mLaunchingBoundsController;
+    LaunchParamsController getLaunchParamsController() {
+        return mLaunchParamsController;
     }
 
     protected <T extends ActivityStack> T getStack(int stackId) {
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 6684f25..0480646 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -30,6 +30,7 @@
 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
 
 import android.app.ActivityOptions;
+import android.app.AppGlobals;
 import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
@@ -40,10 +41,12 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.os.Binder;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.HarmfulAppWarningActivity;
 import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.server.LocalServices;
 
@@ -115,6 +118,15 @@
         mCallingPackage = callingPackage;
     }
 
+    private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
+        final IIntentSender target = mService.getIntentSenderLocked(
+                INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/,
+                null /*resultCode*/, 0 /*requestCode*/,
+                new Intent[] { mIntent }, new String[] { mResolvedType },
+                flags, null /*bOptions*/);
+        return new IntentSender(target);
+    }
+
     /**
      * Intercept the launch intent based on various signals. If an interception happened the
      * internal variables get assigned and need to be read explicitly by the caller.
@@ -144,6 +156,11 @@
             // be unlocked when profile's user is running.
             return true;
         }
+        if (interceptHarmfulAppIfNeeded()) {
+            // If the app has a "harmful app" warning associated with it, we should ask to uninstall
+            // before issuing the work challenge.
+            return true;
+        }
         return interceptWorkProfileChallengeIfNeeded();
     }
 
@@ -152,13 +169,10 @@
         if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
             return false;
         }
-        IIntentSender target = mService.getIntentSenderLocked(
-                INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingUid, mUserId, null, null, 0,
-                new Intent[] {mIntent}, new String[] {mResolvedType},
-                FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT, null);
+        IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
+                FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT);
 
-        mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId,
-                new IntentSender(target));
+        mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target);
         mCallingPid = mRealCallingPid;
         mCallingUid = mRealCallingUid;
         mResolvedType = null;
@@ -240,11 +254,8 @@
             return null;
         }
         // TODO(b/28935539): should allow certain activities to bypass work challenge
-        final IIntentSender target = mService.getIntentSenderLocked(
-                INTENT_SENDER_ACTIVITY, callingPackage,
-                Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
-                new String[]{ resolvedType },
-                FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
+        final IntentSender target = createIntentSenderForOriginalIntent(Binder.getCallingUid(),
+                FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
         final KeyguardManager km = (KeyguardManager) mServiceContext
                 .getSystemService(KEYGUARD_SERVICE);
         final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
@@ -254,8 +265,36 @@
         newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
                 FLAG_ACTIVITY_TASK_ON_HOME);
         newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
-        newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
+        newIntent.putExtra(EXTRA_INTENT, target);
         return newIntent;
     }
 
+    private boolean interceptHarmfulAppIfNeeded() {
+        CharSequence harmfulAppWarning;
+        try {
+            harmfulAppWarning = AppGlobals.getPackageManager().getHarmfulAppWarning(
+                    mAInfo.packageName, mUserId);
+        } catch (RemoteException e) {
+            return false;
+        }
+
+        if (harmfulAppWarning == null) {
+            return false;
+        }
+
+        final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
+                FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
+
+        mIntent = HarmfulAppWarningActivity.createHarmfulAppWarningIntent(mServiceContext,
+                mAInfo.packageName, target, harmfulAppWarning);
+
+        mCallingPid = mRealCallingPid;
+        mCallingUid = mRealCallingUid;
+        mResolvedType = null;
+
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+        return true;
+    }
+
 }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index abdbfad..3a13155 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -96,7 +96,6 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.voice.IVoiceInteractionSession;
@@ -109,6 +108,7 @@
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
+import com.android.server.am.LaunchParamsController.LaunchParams;
 import com.android.server.pm.InstantAppResolver;
 
 import java.io.PrintWriter;
@@ -144,7 +144,7 @@
     private boolean mLaunchTaskBehind;
     private int mLaunchFlags;
 
-    private Rect mLaunchBounds = new Rect();
+    private LaunchParams mLaunchParams = new LaunchParams();
 
     private ActivityRecord mNotTop;
     private boolean mDoResume;
@@ -318,6 +318,13 @@
         boolean mayWait;
 
         /**
+         * Ensure constructed request matches reset instance.
+         */
+        Request() {
+            reset();
+        }
+
+        /**
          * Sets values back to the initial state, clearing any held references.
          */
         void reset() {
@@ -332,8 +339,8 @@
             resultTo = null;
             resultWho = null;
             requestCode = 0;
-            callingPid = 0;
-            callingUid = 0;
+            callingPid = DEFAULT_CALLING_PID;
+            callingUid = DEFAULT_CALLING_UID;
             callingPackage = null;
             realCallingPid = 0;
             realCallingUid = 0;
@@ -412,7 +419,7 @@
         mLaunchFlags = starter.mLaunchFlags;
         mLaunchMode = starter.mLaunchMode;
 
-        mLaunchBounds.set(starter.mLaunchBounds);
+        mLaunchParams.set(starter.mLaunchParams);
 
         mNotTop = starter.mNotTop;
         mDoResume = starter.mDoResume;
@@ -1147,6 +1154,18 @@
             preferredLaunchDisplayId = mOptions.getLaunchDisplayId();
         }
 
+        // windowing mode and preferred launch display values from {@link LaunchParams} take
+        // priority over those specified in {@link ActivityOptions}.
+        if (!mLaunchParams.isEmpty()) {
+            if (mLaunchParams.hasPreferredDisplay()) {
+                preferredLaunchDisplayId = mLaunchParams.mPreferredDisplayId;
+            }
+
+            if (mLaunchParams.hasWindowingMode()) {
+                preferredWindowingMode = mLaunchParams.mWindowingMode;
+            }
+        }
+
         if (reusedActivity != null) {
             // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
             // still needs to be a lock task mode violation since the task gets cleared out and
@@ -1371,7 +1390,7 @@
         mLaunchFlags = 0;
         mLaunchMode = INVALID_LAUNCH_MODE;
 
-        mLaunchBounds.setEmpty();
+        mLaunchParams.reset();
 
         mNotTop = null;
         mDoResume = false;
@@ -1418,10 +1437,10 @@
 
         mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options);
 
-        mLaunchBounds.setEmpty();
+        mLaunchParams.reset();
 
-        mSupervisor.getLaunchingBoundsController().calculateBounds(inTask, null /*layout*/, r,
-                sourceRecord, options, mLaunchBounds);
+        mSupervisor.getLaunchParamsController().calculate(inTask, null /*layout*/, r, sourceRecord,
+                options, mLaunchParams);
 
         mLaunchMode = r.launchMode;
 
@@ -1931,7 +1950,7 @@
                     mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity, mSourceRecord,
                     mOptions);
             addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
-            updateBounds(mStartActivity.getTask(), mLaunchBounds);
+            updateBounds(mStartActivity.getTask(), mLaunchParams.mBounds);
 
             if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
                     + " in new task " + mStartActivity.getTask());
@@ -2095,7 +2114,7 @@
             return START_TASK_TO_FRONT;
         }
 
-        if (!mLaunchBounds.isEmpty()) {
+        if (!mLaunchParams.mBounds.isEmpty()) {
             // TODO: Shouldn't we already know what stack to use by the time we get here?
             ActivityStack stack = mSupervisor.getLaunchStack(null, null, mInTask, ON_TOP);
             if (stack != mInTask.getStack()) {
@@ -2104,7 +2123,7 @@
                 mTargetStack = mInTask.getStack();
             }
 
-            updateBounds(mInTask, mLaunchBounds);
+            updateBounds(mInTask, mLaunchParams.mBounds);
         }
 
         mTargetStack.moveTaskToFrontLocked(
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c9aa9a2..81e8eb0 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -933,21 +933,6 @@
         }
     }
 
-    public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
-        }
-    }
-
-    @Override
-    public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
-        }
-    }
-
     @Override
     public void noteNetworkInterfaceType(String iface, int networkType) {
         enforceCallingPermission();
diff --git a/services/core/java/com/android/server/am/ClientLifecycleManager.java b/services/core/java/com/android/server/am/ClientLifecycleManager.java
index 014f708..ae8d9fc 100644
--- a/services/core/java/com/android/server/am/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/am/ClientLifecycleManager.java
@@ -21,6 +21,7 @@
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.ClientTransactionItem;
 import android.app.servertransaction.ActivityLifecycleItem;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -42,9 +43,14 @@
      * @see ClientTransaction
      */
     void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
+        final IApplicationThread client = transaction.getClient();
         transaction.schedule();
-        // TODO: b/70616950
-        //transaction.recycle();
+        if (!(client instanceof Binder)) {
+            // If client is not an instance of Binder - it's a remote call and at this point it is
+            // safe to recycle the object. All objects used for local calls will be recycled after
+            // the transaction is executed on client in ActivityThread.
+            transaction.recycle();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
index 5632fc0..c9afc17 100644
--- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
@@ -37,7 +37,8 @@
 
     private static final String[][] sGlobalSettingsMapping = new String[][] {
     //  List mapping entries in the following format:
-    //            {Settings.Global.SETTING_NAME, "system_property_name"},
+    //  {Settings.Global.SETTING_NAME, "system_property_name"},
+        {Settings.Global.SYS_VDSO, "sys.vdso"},
     };
 
 
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 35f4f25..4d7bc1e 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -150,7 +150,7 @@
         }
     }
 
-    void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
+    void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message) {
         final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
         if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
             failCallback(callback);
@@ -164,7 +164,7 @@
             mStackSupervisor.wakeUp("dismissKeyguard");
         }
 
-        mWindowManager.dismissKeyguard(callback);
+        mWindowManager.dismissKeyguard(callback, message);
     }
 
     private void setKeyguardGoingAway(boolean keyguardGoingAway) {
@@ -304,7 +304,7 @@
         // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
         if (!mOccluded && mDismissingKeyguardActivity != null
                 && mWindowManager.isKeyguardSecure()) {
-            mWindowManager.dismissKeyguard(null /* callback */);
+            mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
             mDismissalRequested = true;
 
             // If we are about to unocclude the Keyguard, but we can dismiss it without security,
diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/am/LaunchParamsController.java
new file mode 100644
index 0000000..7ab7f98
--- /dev/null
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import android.annotation.IntDef;
+import android.app.ActivityOptions;
+import android.content.pm.ActivityInfo.WindowLayout;
+import android.graphics.Rect;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
+
+/**
+ * {@link LaunchParamsController} calculates the {@link LaunchParams} by coordinating between
+ * registered {@link LaunchParamsModifier}s.
+ */
+class LaunchParamsController {
+    private final ActivityManagerService mService;
+    private final List<LaunchParamsModifier> mModifiers = new ArrayList<>();
+
+    // Temporary {@link LaunchParams} for internal calculations. This is kept separate from
+    // {@code mTmpCurrent} and {@code mTmpResult} to prevent clobbering values.
+    private final LaunchParams mTmpParams = new LaunchParams();
+
+    private final LaunchParams mTmpCurrent = new LaunchParams();
+    private final LaunchParams mTmpResult = new LaunchParams();
+
+    LaunchParamsController(ActivityManagerService service) {
+       mService = service;
+    }
+
+    /**
+     * Creates a {@link LaunchParamsController} with default registered
+     * {@link LaunchParamsModifier}s.
+     */
+    void registerDefaultModifiers(ActivityStackSupervisor supervisor) {
+        // {@link TaskLaunchParamsModifier} handles window layout preferences.
+        registerModifier(new TaskLaunchParamsModifier());
+
+        // {@link ActivityLaunchParamsModifier} is the most specific modifier and thus should be
+        // registered last (applied first) out of the defaults.
+        registerModifier(new ActivityLaunchParamsModifier(supervisor));
+    }
+
+    /**
+     * Returns the {@link LaunchParams} calculated by the registered modifiers
+     * @param task      The {@link TaskRecord} currently being positioned.
+     * @param layout    The specified {@link WindowLayout}.
+     * @param activity  The {@link ActivityRecord} currently being positioned.
+     * @param source    The {@link ActivityRecord} from which activity was started from.
+     * @param options   The {@link ActivityOptions} specified for the activity.
+     * @param result    The resulting params.
+     */
+    void calculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+                   ActivityRecord source, ActivityOptions options, LaunchParams result) {
+        result.reset();
+
+        // We start at the last registered {@link LaunchParamsModifier} as this represents
+        // The modifier closest to the product level. Moving back through the list moves closer to
+        // the platform logic.
+        for (int i = mModifiers.size() - 1; i >= 0; --i) {
+            mTmpCurrent.set(result);
+            mTmpResult.reset();
+            final LaunchParamsModifier modifier = mModifiers.get(i);
+
+            switch(modifier.onCalculate(task, layout, activity, source, options, mTmpCurrent,
+                    mTmpResult)) {
+                case RESULT_SKIP:
+                    // Do not apply any results when we are told to skip
+                    continue;
+                case RESULT_DONE:
+                    // Set result and return immediately.
+                    result.set(mTmpResult);
+                    return;
+                case RESULT_CONTINUE:
+                    // Set result and continue
+                    result.set(mTmpResult);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * A convenience method for laying out a task.
+     * @return {@code true} if bounds were set on the task. {@code false} otherwise.
+     */
+    boolean layoutTask(TaskRecord task, WindowLayout layout) {
+        return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
+    }
+
+    boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+            ActivityRecord source, ActivityOptions options) {
+        calculate(task, layout, activity, source, options, mTmpParams);
+
+        // No changes, return.
+        if (mTmpParams.isEmpty()) {
+            return false;
+        }
+
+        mService.mWindowManager.deferSurfaceLayout();
+
+        try {
+            if (mTmpParams.hasPreferredDisplay()
+                    && mTmpParams.mPreferredDisplayId != task.getStack().getDisplay().mDisplayId) {
+                mService.moveStackToDisplay(task.getStackId(), mTmpParams.mPreferredDisplayId);
+            }
+
+            if (mTmpParams.hasWindowingMode()
+                    && mTmpParams.mWindowingMode != task.getStack().getWindowingMode()) {
+                task.getStack().setWindowingMode(mTmpParams.mWindowingMode);
+            }
+
+            if (!mTmpParams.mBounds.isEmpty()) {
+                task.updateOverrideConfiguration(mTmpParams.mBounds);
+                return true;
+            } else {
+                return false;
+            }
+        } finally {
+            mService.mWindowManager.continueSurfaceLayout();
+        }
+    }
+
+    /**
+     * Adds a modifier to participate in future bounds calculation. Note that the last registered
+     * {@link LaunchParamsModifier} will be the first to calculate the bounds.
+     */
+    void registerModifier(LaunchParamsModifier modifier) {
+        if (mModifiers.contains(modifier)) {
+            return;
+        }
+
+        mModifiers.add(modifier);
+    }
+
+    /**
+     * A container for holding launch related fields.
+     */
+    static class LaunchParams {
+        /** The bounds within the parent container. */
+        final Rect mBounds = new Rect();
+
+        /** The id of the display the {@link TaskRecord} would prefer to be on. */
+        int mPreferredDisplayId;
+
+        /** The windowing mode to be in. */
+        int mWindowingMode;
+
+        /** Sets values back to default. {@link #isEmpty} will return {@code true} once called. */
+        void reset() {
+            mBounds.setEmpty();
+            mPreferredDisplayId = INVALID_DISPLAY;
+            mWindowingMode = WINDOWING_MODE_UNDEFINED;
+        }
+
+        /** Copies the values set on the passed in {@link LaunchParams}. */
+        void set(LaunchParams params) {
+            mBounds.set(params.mBounds);
+            mPreferredDisplayId = params.mPreferredDisplayId;
+            mWindowingMode = params.mWindowingMode;
+        }
+
+        /** Returns {@code true} if no values have been explicitly set. */
+        boolean isEmpty() {
+            return mBounds.isEmpty() && mPreferredDisplayId == INVALID_DISPLAY
+                    && mWindowingMode == WINDOWING_MODE_UNDEFINED;
+        }
+
+        boolean hasWindowingMode() {
+            return mWindowingMode != WINDOWING_MODE_UNDEFINED;
+        }
+
+        boolean hasPreferredDisplay() {
+            return mPreferredDisplayId != INVALID_DISPLAY;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            LaunchParams that = (LaunchParams) o;
+
+            if (mPreferredDisplayId != that.mPreferredDisplayId) return false;
+            if (mWindowingMode != that.mWindowingMode) return false;
+            return mBounds != null ? mBounds.equals(that.mBounds) : that.mBounds == null;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mBounds != null ? mBounds.hashCode() : 0;
+            result = 31 * result + mPreferredDisplayId;
+            result = 31 * result + mWindowingMode;
+            return result;
+        }
+    }
+
+    /**
+     * An interface implemented by those wanting to participate in bounds calculation.
+     */
+    interface LaunchParamsModifier {
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
+        @interface Result {}
+
+        // Returned when the modifier does not want to influence the bounds calculation
+        int RESULT_SKIP = 0;
+        // Returned when the modifier has changed the bounds and would like its results to be the
+        // final bounds applied.
+        int RESULT_DONE = 1;
+        // Returned when the modifier has changed the bounds but is okay with other modifiers
+        // influencing the bounds.
+        int RESULT_CONTINUE = 2;
+
+        /**
+         * Called when asked to calculate {@link LaunchParams}.
+         * @param task            The {@link TaskRecord} currently being positioned.
+         * @param layout          The specified {@link WindowLayout}.
+         * @param activity        The {@link ActivityRecord} currently being positioned.
+         * @param source          The {@link ActivityRecord} activity was started from.
+         * @param options         The {@link ActivityOptions} specified for the activity.
+         * @param currentParams   The current {@link LaunchParams}. This can differ from the initial
+         *                        params as it represents the modified params up to this point.
+         * @param outParams       The resulting {@link LaunchParams} after all calculations.
+         * @return                A {@link Result} representing the result of the
+         *                        {@link LaunchParams} calculation.
+         */
+        @Result
+        int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+                ActivityRecord source, ActivityOptions options, LaunchParams currentParams,
+                LaunchParams outParams);
+    }
+}
diff --git a/services/core/java/com/android/server/am/LaunchingBoundsController.java b/services/core/java/com/android/server/am/LaunchingBoundsController.java
deleted file mode 100644
index 5aa7f58..0000000
--- a/services/core/java/com/android/server/am/LaunchingBoundsController.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.am;
-
-import android.annotation.IntDef;
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo.WindowLayout;
-import android.graphics.Rect;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_CONTINUE;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_DONE;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_SKIP;
-
-/**
- * {@link LaunchingBoundsController} calculates the launch bounds by coordinating between registered
- * {@link LaunchingBoundsPositioner}.
- */
-class LaunchingBoundsController {
-    private final List<LaunchingBoundsPositioner> mPositioners = new ArrayList<>();
-
-    // Temporary {@link Rect} for calculations. This is kept separate from {@code mTmpCurrent} and
-    // {@code mTmpResult} to prevent clobbering values.
-    private final Rect mTmpRect = new Rect();
-
-    private final Rect mTmpCurrent = new Rect();
-    private final Rect mTmpResult = new Rect();
-
-    /**
-     * Creates a {@link LaunchingBoundsController} with default registered
-     * {@link LaunchingBoundsPositioner}s.
-     */
-    void registerDefaultPositioners(ActivityStackSupervisor supervisor) {
-        // {@link LaunchingTaskPositioner} handles window layout preferences.
-        registerPositioner(new LaunchingTaskPositioner());
-
-        // {@link LaunchingActivityPositioner} is the most specific positioner and thus should be
-        // registered last (applied first) out of the defaults.
-        registerPositioner(new LaunchingActivityPositioner(supervisor));
-    }
-
-    /**
-     * Returns the position calculated by the registered positioners
-     * @param task      The {@link TaskRecord} currently being positioned.
-     * @param layout    The specified {@link WindowLayout}.
-     * @param activity  The {@link ActivityRecord} currently being positioned.
-     * @param source    The {@link ActivityRecord} from which activity was started from.
-     * @param options   The {@link ActivityOptions} specified for the activity.
-     * @param result    The resulting bounds. If no bounds are set, {@link Rect#isEmpty()} will be
-     *                  {@code true}.
-     */
-    void calculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity,
-            ActivityRecord source, ActivityOptions options, Rect result) {
-        result.setEmpty();
-
-        // We start at the last registered {@link LaunchingBoundsPositioner} as this represents
-        // The positioner closest to the product level. Moving back through the list moves closer to
-        // the platform logic.
-        for (int i = mPositioners.size() - 1; i >= 0; --i) {
-            mTmpResult.setEmpty();
-            mTmpCurrent.set(result);
-            final LaunchingBoundsPositioner positioner = mPositioners.get(i);
-
-            switch(positioner.onCalculateBounds(task, layout, activity, source, options,
-                    mTmpCurrent, mTmpResult)) {
-                case RESULT_SKIP:
-                    // Do not apply any results when we are told to skip
-                    continue;
-                case RESULT_DONE:
-                    // Set result and return immediately.
-                    result.set(mTmpResult);
-                    return;
-                case RESULT_CONTINUE:
-                    // Set result and continue
-                    result.set(mTmpResult);
-                    break;
-            }
-        }
-    }
-
-    /**
-     * A convenience method for laying out a task.
-     * @return {@code true} if bounds were set on the task. {@code false} otherwise.
-     */
-    boolean layoutTask(TaskRecord task, WindowLayout layout) {
-        return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
-    }
-
-    boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
-            ActivityRecord source, ActivityOptions options) {
-        calculateBounds(task, layout, activity, source, options, mTmpRect);
-
-        if (mTmpRect.isEmpty()) {
-            return false;
-        }
-
-        task.updateOverrideConfiguration(mTmpRect);
-
-        return true;
-    }
-
-    /**
-     * Adds a positioner to participate in future bounds calculation. Note that the last registered
-     * {@link LaunchingBoundsPositioner} will be the first to calculate the bounds.
-     */
-    void registerPositioner(LaunchingBoundsPositioner positioner) {
-        if (mPositioners.contains(positioner)) {
-            return;
-        }
-
-        mPositioners.add(positioner);
-    }
-
-    /**
-     * An interface implemented by those wanting to participate in bounds calculation.
-     */
-    interface LaunchingBoundsPositioner {
-        @Retention(RetentionPolicy.SOURCE)
-        @IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
-        @interface Result {}
-
-        // Returned when the positioner does not want to influence the bounds calculation
-        int RESULT_SKIP = 0;
-        // Returned when the positioner has changed the bounds and would like its results to be the
-        // final bounds applied.
-        int RESULT_DONE = 1;
-        // Returned when the positioner has changed the bounds but is okay with other positioners
-        // influencing the bounds.
-        int RESULT_CONTINUE = 2;
-
-        /**
-         * Called when asked to calculate bounds.
-         * @param task      The {@link TaskRecord} currently being positioned.
-         * @param layout    The specified {@link WindowLayout}.
-         * @param activity  The {@link ActivityRecord} currently being positioned.
-         * @param source    The {@link ActivityRecord} activity was started from.
-         * @param options   The {@link ActivityOptions} specified for the activity.
-         * @param current   The current bounds. This can differ from the initial bounds as it
-         *                  represents the modified bounds up to this point.
-         * @param result    The {@link Rect} which the positioner should return its modified bounds.
-         *                  Any merging of the current bounds should be already applied to this
-         *                  value as well before returning.
-         * @return          A {@link Result} representing the result of the bounds calculation.
-         */
-        @Result
-        int onCalculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity,
-                ActivityRecord source, ActivityOptions options, Rect current, Rect result);
-    }
-}
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index ba3e25a..21f9135 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -752,7 +752,7 @@
                     USER_CURRENT) != 0;
             if (shouldLockKeyguard) {
                 mWindowManager.lockNow(null);
-                mWindowManager.dismissKeyguard(null /* callback */);
+                mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
                 getLockPatternUtils().requireCredentialEntry(USER_ALL);
             }
         } catch (Settings.SettingNotFoundException e) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b39e96d..77f5c16 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -358,12 +358,12 @@
             case ActivityManager.PROCESS_STATE_TOP:
                 procState = "TOP ";
                 break;
-            case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
-                procState = "BFGS";
-                break;
             case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
                 procState = "FGS ";
                 break;
+            case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+                procState = "BFGS";
+                break;
             case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
                 procState = "IMPF";
                 break;
@@ -498,8 +498,8 @@
         PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT
         PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PROC_MEM_TOP,                   // ActivityManager.PROCESS_STATE_TOP
-        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
@@ -520,8 +520,8 @@
         PSS_FIRST_PERSISTENT_INTERVAL,  // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_FIRST_PERSISTENT_INTERVAL,  // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_FIRST_TOP_INTERVAL,         // ActivityManager.PROCESS_STATE_TOP
-        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
@@ -542,8 +542,8 @@
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_SAME_TOP_INTERVAL,          // ActivityManager.PROCESS_STATE_TOP
-        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
@@ -564,8 +564,8 @@
         PSS_FIRST_ASLEEP_PERSISTENT_INTERVAL,   // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_FIRST_ASLEEP_PERSISTENT_INTERVAL,   // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_FIRST_ASLEEP_TOP_INTERVAL,          // ActivityManager.PROCESS_STATE_TOP
-        PSS_FIRST_ASLEEP_BACKGROUND_INTERVAL,   // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_FIRST_ASLEEP_BACKGROUND_INTERVAL,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_FIRST_ASLEEP_BACKGROUND_INTERVAL,   // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_FIRST_ASLEEP_BACKGROUND_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_FIRST_ASLEEP_BACKGROUND_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_FIRST_ASLEEP_BACKGROUND_INTERVAL,   // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
@@ -586,8 +586,9 @@
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_SAME_TOP_INTERVAL,          // ActivityManager.PROCESS_STATE_TOP
-        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
@@ -608,8 +609,8 @@
         PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_TOP
-        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
@@ -630,8 +631,8 @@
         PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_TOP
-        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
similarity index 93%
rename from services/core/java/com/android/server/am/LaunchingTaskPositioner.java
rename to services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
index d89568e..92f1cc3 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
@@ -21,26 +21,27 @@
 
 import android.app.ActivityOptions;
 import android.content.pm.ActivityInfo;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.Slog;
 import android.view.Gravity;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.am.LaunchParamsController.LaunchParams;
+import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
 
 import java.util.ArrayList;
 
 /**
  * Determines where a launching task should be positioned and sized on the display.
  *
- * The positioner is fairly simple. For the new task it tries default position based on the gravity
+ * The modifier is fairly simple. For the new task it tries default position based on the gravity
  * and compares corners of the task with corners of existing tasks. If some two pairs of corners are
  * sufficiently close enough, it shifts the bounds of the new task and tries again. When it exhausts
  * all possible shifts, it gives up and puts the task in the original position.
  *
  * Note that the only gravities of concern are the corners and the center.
  */
-class LaunchingTaskPositioner implements LaunchingBoundsController.LaunchingBoundsPositioner {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "LaunchingTaskPositioner" : TAG_AM;
+class TaskLaunchParamsModifier implements LaunchParamsModifier {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskLaunchParamsModifier" : TAG_AM;
 
     // Determines how close window frames/corners have to be to call them colliding.
     private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;
@@ -70,17 +71,15 @@
     private final Rect mTmpProposal = new Rect();
     private final Rect mTmpOriginal = new Rect();
 
-    private final Point mDisplaySize = new Point();
-
     /**
      * Tries to set task's bound in a way that it won't collide with any other task. By colliding
      * we mean that two tasks have left-top corner very close to each other, so one might get
      * obfuscated by the other one.
      */
     @Override
-    public int onCalculateBounds(TaskRecord task, ActivityInfo.WindowLayout layout,
-            ActivityRecord activity, ActivityRecord source,
-            ActivityOptions options, Rect current, Rect result) {
+    public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+                           ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+                           LaunchParams currentParams, LaunchParams outParams) {
         // We can only apply positioning if we're in a freeform stack.
         if (task == null || task.getStack() == null || !task.inFreeformWindowingMode()) {
             return RESULT_SKIP;
@@ -90,9 +89,11 @@
 
         mAvailableRect.set(task.getParent().getBounds());
 
+        final Rect resultBounds = outParams.mBounds;
+
         if (layout == null) {
             positionCenter(tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
-                    getFreeformHeight(mAvailableRect), result);
+                    getFreeformHeight(mAvailableRect), resultBounds);
             return RESULT_CONTINUE;
         }
 
@@ -102,22 +103,22 @@
         int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (verticalGravity == Gravity.TOP) {
             if (horizontalGravity == Gravity.RIGHT) {
-                positionTopRight(tasks, mAvailableRect, width, height, result);
+                positionTopRight(tasks, mAvailableRect, width, height, resultBounds);
             } else {
-                positionTopLeft(tasks, mAvailableRect, width, height, result);
+                positionTopLeft(tasks, mAvailableRect, width, height, resultBounds);
             }
         } else if (verticalGravity == Gravity.BOTTOM) {
             if (horizontalGravity == Gravity.RIGHT) {
-                positionBottomRight(tasks, mAvailableRect, width, height, result);
+                positionBottomRight(tasks, mAvailableRect, width, height, resultBounds);
             } else {
-                positionBottomLeft(tasks, mAvailableRect, width, height, result);
+                positionBottomLeft(tasks, mAvailableRect, width, height, resultBounds);
             }
         } else {
             // Some fancy gravity setting that we don't support yet. We just put the activity in the
             // center.
             Slog.w(TAG, "Received unsupported gravity: " + layout.gravity
                     + ", positioning in the center instead.");
-            positionCenter(tasks, mAvailableRect, width, height, result);
+            positionCenter(tasks, mAvailableRect, width, height, resultBounds);
         }
 
         return RESULT_CONTINUE;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4aef95d..b131e86 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -714,7 +714,7 @@
             } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
                 Rect bounds = getLaunchBounds();
                 if (bounds == null) {
-                    mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(this, null);
+                    mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
                     bounds = configBounds;
                 }
                 kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
@@ -1838,7 +1838,7 @@
             if (mLastNonFullscreenBounds != null) {
                 updateOverrideConfiguration(mLastNonFullscreenBounds);
             } else {
-                mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(this, null);
+                mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
             }
         } else {
             updateOverrideConfiguration(inStack.getOverrideBounds());
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 34621e0..a327a01 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -101,6 +101,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -249,39 +250,51 @@
         }
     }
 
-    void stopRunningUsersLU(int maxRunningUsers) {
-        int currentlyRunning = mUserLru.size();
-        int i = 0;
-        while (currentlyRunning > maxRunningUsers && i < mUserLru.size()) {
-            Integer oldUserId = mUserLru.get(i);
-            UserState oldUss = mStartedUsers.get(oldUserId);
-            if (oldUss == null) {
+    List<Integer> getRunningUsersLU() {
+        ArrayList<Integer> runningUsers = new ArrayList<>();
+        for (Integer userId : mUserLru) {
+            UserState uss = mStartedUsers.get(userId);
+            if (uss == null) {
                 // Shouldn't happen, but be sane if it does.
-                mUserLru.remove(i);
-                currentlyRunning--;
                 continue;
             }
-            if (oldUss.state == UserState.STATE_STOPPING
-                    || oldUss.state == UserState.STATE_SHUTDOWN) {
+            if (uss.state == UserState.STATE_STOPPING
+                    || uss.state == UserState.STATE_SHUTDOWN) {
                 // This user is already stopping, doesn't count.
-                currentlyRunning--;
-                i++;
                 continue;
             }
-            if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) {
-                // Owner/System user and current user can't be stopped. We count it as running
-                // when it is not a pure system user.
-                if (UserInfo.isSystemOnly(oldUserId)) {
-                    currentlyRunning--;
+            if (userId == UserHandle.USER_SYSTEM) {
+                // We only count system user as running when it is not a pure system user.
+                if (UserInfo.isSystemOnly(userId)) {
+                    continue;
                 }
-                i++;
+            }
+            runningUsers.add(userId);
+        }
+        return runningUsers;
+    }
+
+    void stopRunningUsersLU(int maxRunningUsers) {
+        List<Integer> currentlyRunning = getRunningUsersLU();
+        Iterator<Integer> iterator = currentlyRunning.iterator();
+        while (currentlyRunning.size() > maxRunningUsers && iterator.hasNext()) {
+            Integer userId = iterator.next();
+            if (userId == UserHandle.USER_SYSTEM || userId == mCurrentUserId) {
+                // Owner/System user and current user can't be stopped
                 continue;
             }
-            // This is a user to be stopped.
-            if (stopUsersLU(oldUserId, false, null) == USER_OP_SUCCESS) {
-                currentlyRunning--;
+            if (stopUsersLU(userId, false, null) == USER_OP_SUCCESS) {
+                iterator.remove();
             }
-            i++;
+        }
+    }
+
+    /**
+     * Returns if more users can be started without stopping currently running users.
+     */
+    boolean canStartMoreUsers() {
+        synchronized (mLock) {
+            return getRunningUsersLU().size() < mMaxRunningUsers;
         }
     }
 
@@ -768,34 +781,23 @@
     /**
      * Stops the guest or ephemeral user if it has gone to the background.
      */
-    private void stopGuestOrEphemeralUserIfBackground() {
-        IntArray userIds = new IntArray();
-        synchronized (mLock) {
-            final int num = mUserLru.size();
-            for (int i = 0; i < num; i++) {
-                Integer oldUserId = mUserLru.get(i);
-                UserState oldUss = mStartedUsers.get(oldUserId);
-                if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId
-                        || oldUss.state == UserState.STATE_STOPPING
-                        || oldUss.state == UserState.STATE_SHUTDOWN) {
-                    continue;
-                }
-                userIds.add(oldUserId);
-            }
+    private void stopGuestOrEphemeralUserIfBackground(int oldUserId) {
+        if (DEBUG_MU) Slog.i(TAG, "Stop guest or ephemeral user if background: " + oldUserId);
+        UserState oldUss = mStartedUsers.get(oldUserId);
+        if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId
+                || oldUss.state == UserState.STATE_STOPPING
+                || oldUss.state == UserState.STATE_SHUTDOWN) {
+            return;
         }
-        final int userIdsSize = userIds.size();
-        for (int i = 0; i < userIdsSize; i++) {
-            int oldUserId = userIds.get(i);
-            UserInfo userInfo = getUserInfo(oldUserId);
-            if (userInfo.isEphemeral()) {
-                LocalServices.getService(UserManagerInternal.class).onEphemeralUserStop(oldUserId);
-            }
-            if (userInfo.isGuest() || userInfo.isEphemeral()) {
-                // This is a user to be stopped.
-                synchronized (mLock) {
-                    stopUsersLU(oldUserId, true, null);
-                }
-                break;
+
+        UserInfo userInfo = getUserInfo(oldUserId);
+        if (userInfo.isEphemeral()) {
+            LocalServices.getService(UserManagerInternal.class).onEphemeralUserStop(oldUserId);
+        }
+        if (userInfo.isGuest() || userInfo.isEphemeral()) {
+            // This is a user to be stopped.
+            synchronized (mLock) {
+                stopUsersLU(oldUserId, true, null);
             }
         }
     }
@@ -1333,7 +1335,7 @@
         mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
         mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
                 newUserId, 0));
-        stopGuestOrEphemeralUserIfBackground();
+        stopGuestOrEphemeralUserIfBackground(oldUserId);
         stopBackgroundUsersIfEnforced(oldUserId);
     }
 
@@ -1762,6 +1764,20 @@
         }
     }
 
+    void onUserRemoved(int userId) {
+        synchronized (mLock) {
+            int size = mUserProfileGroupIds.size();
+            for (int i = size - 1; i >= 0; i--) {
+                if (mUserProfileGroupIds.keyAt(i) == userId
+                        || mUserProfileGroupIds.valueAt(i) == userId) {
+                    mUserProfileGroupIds.removeAt(i);
+
+                }
+            }
+            mCurrentProfileIds = ArrayUtils.removeInt(mCurrentProfileIds, userId);
+        }
+    }
+
     /**
      * Returns whether the given user requires credential entry at this time. This is used to
      * intercept activity launches for work apps when the Work Challenge is present.
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
index 7d3b670..10e6cad 100644
--- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
@@ -25,6 +25,7 @@
 import android.hardware.radio.ITunerCallback;
 import android.hardware.radio.RadioManager;
 import android.os.ParcelableException;
+import android.os.RemoteException;
 import android.util.Slog;
 
 import com.android.server.SystemService;
@@ -86,7 +87,7 @@
 
         @Override
         public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig,
-                boolean withAudio, ITunerCallback callback) {
+                boolean withAudio, ITunerCallback callback) throws RemoteException {
             Slog.i(TAG, "openTuner(" + moduleId + ", _, " + withAudio + ", _)");
             enforcePolicyAccess();
             if (callback == null) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index e5090ed..f9b35f5 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -21,6 +21,7 @@
 import android.graphics.BitmapFactory;
 import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
+import android.hardware.radio.ProgramList;
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.os.IBinder;
@@ -249,8 +250,7 @@
         }
     }
 
-    @Override
-    public List<RadioManager.ProgramInfo> getProgramList(Map vendorFilter) {
+    List<RadioManager.ProgramInfo> getProgramList(Map vendorFilter) {
         Map<String, String> sFilter = vendorFilter;
         synchronized (mLock) {
             checkNotClosedLocked();
@@ -263,6 +263,16 @@
     }
 
     @Override
+    public void startProgramListUpdates(ProgramList.Filter filter) {
+        mTunerCallback.startProgramListUpdates(filter);
+    }
+
+    @Override
+    public void stopProgramListUpdates() {
+        mTunerCallback.stopProgramListUpdates();
+    }
+
+    @Override
     public boolean isConfigFlagSupported(int flag) {
         return flag == RadioManager.CONFIG_FORCE_ANALOG;
     }
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 673ff88..18f56ed 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
+import android.hardware.radio.ProgramList;
 import android.hardware.radio.RadioManager;
 import android.hardware.radio.RadioMetadata;
 import android.hardware.radio.RadioTuner;
@@ -28,6 +29,10 @@
 
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
 
 class TunerCallback implements ITunerCallback {
     private static final String TAG = "BroadcastRadioService.TunerCallback";
@@ -40,6 +45,8 @@
     @NonNull private final Tuner mTuner;
     @NonNull private final ITunerCallback mClientCallback;
 
+    private final AtomicReference<ProgramList.Filter> mProgramListFilter = new AtomicReference<>();
+
     TunerCallback(@NonNull Tuner tuner, @NonNull ITunerCallback clientCallback, int halRev) {
         mTuner = tuner;
         mClientCallback = clientCallback;
@@ -78,6 +85,15 @@
         mTuner.close();
     }
 
+    void startProgramListUpdates(@NonNull ProgramList.Filter filter) {
+        mProgramListFilter.set(Objects.requireNonNull(filter));
+        sendProgramListUpdate();
+    }
+
+    void stopProgramListUpdates() {
+        mProgramListFilter.set(null);
+    }
+
     @Override
     public void onError(int status) {
         dispatch(() -> mClientCallback.onError(status));
@@ -121,6 +137,28 @@
     @Override
     public void onProgramListChanged() {
         dispatch(() -> mClientCallback.onProgramListChanged());
+        sendProgramListUpdate();
+    }
+
+    private void sendProgramListUpdate() {
+        ProgramList.Filter filter = mProgramListFilter.get();
+        if (filter == null) return;
+
+        List<RadioManager.ProgramInfo> modified;
+        try {
+            modified = mTuner.getProgramList(filter.getVendorFilter());
+        } catch (IllegalStateException ex) {
+            Slog.d(TAG, "Program list not ready yet");
+            return;
+        }
+        Set<RadioManager.ProgramInfo> modifiedSet = modified.stream().collect(Collectors.toSet());
+        ProgramList.Chunk chunk = new ProgramList.Chunk(true, true, modifiedSet, null);
+        dispatch(() -> mClientCallback.onProgramListUpdated(chunk));
+    }
+
+    @Override
+    public void onProgramListUpdated(ProgramList.Chunk chunk) {
+        dispatch(() -> mClientCallback.onProgramListUpdated(chunk));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 9158ff0..fc9a5d6 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -82,7 +82,7 @@
     }
 
     public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig,
-        boolean withAudio, @NonNull ITunerCallback callback) {
+        boolean withAudio, @NonNull ITunerCallback callback) throws RemoteException {
         Objects.requireNonNull(callback);
 
         if (!withAudio) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 2c129bb..60a927c 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -20,15 +20,22 @@
 import android.annotation.Nullable;
 import android.hardware.broadcastradio.V2_0.AmFmBandRange;
 import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
+import android.hardware.broadcastradio.V2_0.ProgramFilter;
+import android.hardware.broadcastradio.V2_0.ProgramIdentifier;
+import android.hardware.broadcastradio.V2_0.ProgramInfo;
+import android.hardware.broadcastradio.V2_0.ProgramInfoFlags;
+import android.hardware.broadcastradio.V2_0.ProgramListChunk;
 import android.hardware.broadcastradio.V2_0.Properties;
 import android.hardware.broadcastradio.V2_0.Result;
 import android.hardware.broadcastradio.V2_0.VendorKeyValue;
+import android.hardware.radio.ProgramList;
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.os.ParcelableException;
 import android.util.Slog;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -36,6 +43,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 class Convert {
     private static final String TAG = "BcRadio2Srv.convert";
@@ -78,43 +86,52 @@
         return map;
     }
 
+    private static @ProgramSelector.ProgramType int identifierTypeToProgramType(
+            @ProgramSelector.IdentifierType int idType) {
+        switch (idType) {
+            case ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY:
+            case ProgramSelector.IDENTIFIER_TYPE_RDS_PI:
+                // TODO(b/69958423): verify AM/FM with frequency range
+                return ProgramSelector.PROGRAM_TYPE_FM;
+            case ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT:
+                // TODO(b/69958423): verify AM/FM with frequency range
+                return ProgramSelector.PROGRAM_TYPE_FM_HD;
+            case ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC:
+            case ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE:
+            case ProgramSelector.IDENTIFIER_TYPE_DAB_SCID:
+            case ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY:
+                return ProgramSelector.PROGRAM_TYPE_DAB;
+            case ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID:
+            case ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY:
+                return ProgramSelector.PROGRAM_TYPE_DRMO;
+            case ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID:
+            case ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL:
+                return ProgramSelector.PROGRAM_TYPE_SXM;
+        }
+        if (idType >= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_START
+                && idType <= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_END) {
+            return idType;
+        }
+        return ProgramSelector.PROGRAM_TYPE_INVALID;
+    }
+
     private static @NonNull int[]
     identifierTypesToProgramTypes(@NonNull int[] idTypes) {
         Set<Integer> pTypes = new HashSet<>();
 
         for (int idType : idTypes) {
-            switch (idType) {
-                case ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY:
-                case ProgramSelector.IDENTIFIER_TYPE_RDS_PI:
-                    // TODO(b/69958423): verify AM/FM with region info
-                    pTypes.add(ProgramSelector.PROGRAM_TYPE_AM);
-                    pTypes.add(ProgramSelector.PROGRAM_TYPE_FM);
-                    break;
-                case ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT:
-                    // TODO(b/69958423): verify AM/FM with region info
-                    pTypes.add(ProgramSelector.PROGRAM_TYPE_AM_HD);
-                    pTypes.add(ProgramSelector.PROGRAM_TYPE_FM_HD);
-                    break;
-                case ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC:
-                case ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE:
-                case ProgramSelector.IDENTIFIER_TYPE_DAB_SCID:
-                case ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY:
-                    pTypes.add(ProgramSelector.PROGRAM_TYPE_DAB);
-                    break;
-                case ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID:
-                case ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY:
-                    pTypes.add(ProgramSelector.PROGRAM_TYPE_DRMO);
-                    break;
-                case ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID:
-                case ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL:
-                    pTypes.add(ProgramSelector.PROGRAM_TYPE_SXM);
-                    break;
-                default:
-                    break;
+            int pType = identifierTypeToProgramType(idType);
+
+            if (pType == ProgramSelector.PROGRAM_TYPE_INVALID) continue;
+
+            pTypes.add(pType);
+            if (pType == ProgramSelector.PROGRAM_TYPE_FM) {
+                // TODO(b/69958423): verify AM/FM with region info
+                pTypes.add(ProgramSelector.PROGRAM_TYPE_AM);
             }
-            if (idType >= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_START
-                    && idType <= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_END) {
-                pTypes.add(idType);
+            if (pType == ProgramSelector.PROGRAM_TYPE_FM_HD) {
+                // TODO(b/69958423): verify AM/FM with region info
+                pTypes.add(ProgramSelector.PROGRAM_TYPE_AM_HD);
             }
         }
 
@@ -189,6 +206,64 @@
                 false,  // isBgScanSupported is deprecated
                 supportedProgramTypes,
                 supportedIdentifierTypes,
-                vendorInfoFromHal(prop.vendorInfo));
+                vendorInfoFromHal(prop.vendorInfo)
+        );
+    }
+
+    static @NonNull ProgramIdentifier programIdentifierToHal(
+            @NonNull ProgramSelector.Identifier id) {
+        ProgramIdentifier hwId = new ProgramIdentifier();
+        hwId.type = id.getType();
+        hwId.value = id.getValue();
+        return hwId;
+    }
+
+    static @NonNull ProgramSelector.Identifier programIdentifierFromHal(@NonNull ProgramIdentifier id) {
+        return new ProgramSelector.Identifier(id.type, id.value);
+    }
+
+    static @NonNull ProgramSelector programSelectorFromHal(
+            @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) {
+        ProgramSelector.Identifier[] secondaryIds = sel.secondaryIds.stream().map(
+            id -> programIdentifierFromHal(id)).toArray(ProgramSelector.Identifier[]::new);
+
+        return new ProgramSelector(
+            identifierTypeToProgramType(sel.primaryId.type),
+            programIdentifierFromHal(sel.primaryId),
+            secondaryIds, null);
+    }
+
+    static @NonNull RadioManager.ProgramInfo programInfoFromHal(@NonNull ProgramInfo info) {
+        return new RadioManager.ProgramInfo(
+            programSelectorFromHal(info.selector),
+            (info.infoFlags & ProgramInfoFlags.TUNED) != 0,
+            (info.infoFlags & ProgramInfoFlags.STEREO) != 0,
+            false,  // TODO(b/69860743): digital
+            info.signalQuality,
+            null,  // TODO(b/69860743): metadata
+            info.infoFlags,
+            vendorInfoFromHal(info.vendorInfo)
+        );
+    }
+
+    static @NonNull ProgramFilter programFilterToHal(@NonNull ProgramList.Filter filter) {
+        ProgramFilter hwFilter = new ProgramFilter();
+
+        filter.getIdentifierTypes().stream().forEachOrdered(hwFilter.identifierTypes::add);
+        filter.getIdentifiers().stream().forEachOrdered(
+            id -> hwFilter.identifiers.add(programIdentifierToHal(id)));
+        hwFilter.includeCategories = filter.areCategoriesIncluded();
+        hwFilter.excludeModifications = filter.areModificationsExcluded();
+
+        return hwFilter;
+    }
+
+    static @NonNull ProgramList.Chunk programListChunkFromHal(@NonNull ProgramListChunk chunk) {
+        Set<RadioManager.ProgramInfo> modified = chunk.modified.stream().map(
+            info -> programInfoFromHal(info)).collect(Collectors.toSet());
+        Set<ProgramSelector.Identifier> removed = chunk.removed.stream().map(
+            id -> programIdentifierFromHal(id)).collect(Collectors.toSet());
+
+        return new ProgramList.Chunk(chunk.purge, chunk.complete, modified, removed);
     }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 45b2190..c8e15c1 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -63,20 +63,16 @@
         }
     }
 
-    public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb) {
+    public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb)
+            throws RemoteException {
         TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb));
         Mutable<ITunerSession> hwSession = new Mutable<>();
         MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
 
-        try {
-            mService.openSession(cb, (int result, ITunerSession session) -> {
-                hwSession.value = session;
-                halResult.value = result;
-            });
-        } catch (RemoteException ex) {
-            Slog.e(TAG, "failed to open session", ex);
-            throw new ParcelableException(ex);
-        }
+        mService.openSession(cb, (int result, ITunerSession session) -> {
+            hwSession.value = session;
+            halResult.value = result;
+        });
 
         Convert.throwOnError("openSession", halResult.value);
         Objects.requireNonNull(hwSession.value);
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
index c9084ee..ed2a1b3 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
@@ -56,7 +56,9 @@
     public void onCurrentProgramInfoChanged(ProgramInfo info) {}
 
     @Override
-    public void onProgramListUpdated(ProgramListChunk chunk) {}
+    public void onProgramListUpdated(ProgramListChunk chunk) {
+        dispatch(() -> mClientCb.onProgramListUpdated(Convert.programListChunkFromHal(chunk)));
+    }
 
     @Override
     public void onAntennaStateChange(boolean connected) {}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 8ed646a..e093c9d 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -22,6 +22,7 @@
 import android.hardware.broadcastradio.V2_0.ITunerSession;
 import android.hardware.broadcastradio.V2_0.Result;
 import android.hardware.radio.ITuner;
+import android.hardware.radio.ProgramList;
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.media.AudioSystem;
@@ -184,10 +185,19 @@
     }
 
     @Override
-    public List<RadioManager.ProgramInfo> getProgramList(Map vendorFilter) {
+    public void startProgramListUpdates(ProgramList.Filter filter) throws RemoteException {
         synchronized (mLock) {
             checkNotClosedLocked();
-            return null;
+            int halResult = mHwSession.startProgramListUpdates(Convert.programFilterToHal(filter));
+            Convert.throwOnError("startProgramListUpdates", halResult);
+        }
+    }
+
+    @Override
+    public void stopProgramListUpdates() throws RemoteException {
+        synchronized (mLock) {
+            checkNotClosedLocked();
+            mHwSession.stopProgramListUpdates();
         }
     }
 
@@ -226,17 +236,12 @@
     }
 
     @Override
-    public void setConfigFlag(int flag, boolean value) {
+    public void setConfigFlag(int flag, boolean value) throws RemoteException {
         Slog.v(TAG, "setConfigFlag " + ConfigFlag.toString(flag) + " = " + value);
         synchronized (mLock) {
             checkNotClosedLocked();
 
-            int halResult;
-            try {
-                halResult = mHwSession.setConfigFlag(flag, value);
-            } catch (RemoteException ex) {
-                throw new RuntimeException("Failed to set flag " + ConfigFlag.toString(flag), ex);
-            }
+            int halResult = mHwSession.setConfigFlag(flag, value);
             Convert.throwOnError("setConfigFlag", halResult);
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
new file mode 100644
index 0000000..a4170ce
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
+import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
+import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
+import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
+import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
+import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkUtils;
+import android.os.Binder;
+import android.os.INetworkManagementService;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.server.connectivity.MockableSystemProperties;
+
+import java.net.InetAddress;
+import java.util.Collection;
+
+
+/**
+ * Encapsulate the management of DNS settings for networks.
+ *
+ * This class it NOT designed for concurrent access. Furthermore, all non-static
+ * methods MUST be called from ConnectivityService's thread.
+ *
+ * @hide
+ */
+public class DnsManager {
+    private static final String TAG = DnsManager.class.getSimpleName();
+
+    /* Defaults for resolver parameters. */
+    private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
+    private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
+    private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
+    private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
+
+    private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private final INetworkManagementService mNMS;
+    private final MockableSystemProperties mSystemProperties;
+
+    private int mNumDnsEntries;
+    private int mSampleValidity;
+    private int mSuccessThreshold;
+    private int mMinSamples;
+    private int mMaxSamples;
+    private String mPrivateDnsMode;
+    private String mPrivateDnsSpecifier;
+
+    public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
+        mContext = ctx;
+        mContentResolver = mContext.getContentResolver();
+        mNMS = nms;
+        mSystemProperties = sp;
+
+        // TODO: Create and register ContentObservers to track every setting
+        // used herein, posting messages to respond to changes.
+    }
+
+    public boolean isPrivateDnsInStrictMode() {
+        return !TextUtils.isEmpty(mPrivateDnsMode) &&
+               mPrivateDnsMode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) &&
+               !TextUtils.isEmpty(mPrivateDnsSpecifier);
+    }
+
+    public void setDnsConfigurationForNetwork(
+            int netId, Collection<InetAddress> servers, String domains, boolean isDefaultNetwork) {
+        updateParametersSettings();
+        updatePrivateDnsSettings();
+
+        final String[] serverStrs = NetworkUtils.makeStrings(servers);
+        final String[] domainStrs = (domains == null) ? new String[0] : domains.split(" ");
+        final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
+        final boolean useTls = shouldUseTls(mPrivateDnsMode);
+        // TODO: Populate tlsHostname once it's decided how the hostname's IP
+        // addresses will be resolved:
+        //
+        //     [1] network-provided DNS servers are included here with the
+        //         hostname and netd will use the network-provided servers to
+        //         resolve the hostname and fix up its internal structures, or
+        //
+        //     [2] network-provided DNS servers are included here without the
+        //         hostname, the ConnectivityService layer resolves the given
+        //         hostname, and then reconfigures netd with this information.
+        //
+        // In practice, there will always be a need for ConnectivityService or
+        // the captive portal app to use the network-provided services to make
+        // some queries. This argues in favor of [1], in concert with another
+        // mechanism, perhaps setting a high bit in the netid, to indicate
+        // via existing DNS APIs which set of servers (network-provided or
+        // non-network-provided private DNS) should be queried.
+        final String tlsHostname = "";
+        try {
+            mNMS.setDnsConfigurationForNetwork(
+                    netId, serverStrs, domainStrs, params, useTls, tlsHostname);
+        } catch (Exception e) {
+            Slog.e(TAG, "Error setting DNS configuration: " + e);
+            return;
+        }
+
+        // TODO: netd should listen on [::1]:53 and proxy queries to the current
+        // default network, and we should just set net.dns1 to ::1, not least
+        // because applications attempting to use net.dns resolvers will bypass
+        // the privacy protections of things like DNS-over-TLS.
+        if (isDefaultNetwork) setDefaultDnsSystemProperties(servers);
+        flushVmDnsCache();
+    }
+
+    public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
+        int last = 0;
+        for (InetAddress dns : dnses) {
+            ++last;
+            setNetDnsProperty(last, dns.getHostAddress());
+        }
+        for (int i = last + 1; i <= mNumDnsEntries; ++i) {
+            setNetDnsProperty(i, "");
+        }
+        mNumDnsEntries = last;
+    }
+
+    private void flushVmDnsCache() {
+        /*
+         * Tell the VMs to toss their DNS caches
+         */
+        final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        /*
+         * Connectivity events can happen before boot has completed ...
+         */
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void updatePrivateDnsSettings() {
+        mPrivateDnsMode = getStringSetting(PRIVATE_DNS_MODE);
+        mPrivateDnsSpecifier = getStringSetting(PRIVATE_DNS_SPECIFIER);
+    }
+
+    private void updateParametersSettings() {
+        mSampleValidity = getIntSetting(
+                DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
+                DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
+        if (mSampleValidity < 0 || mSampleValidity > 65535) {
+            Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
+                    DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
+            mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
+        }
+
+        mSuccessThreshold = getIntSetting(
+                DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
+                DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
+        if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
+            Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
+                    DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
+            mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
+        }
+
+        mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
+        mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
+        if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
+            Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
+                    "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
+                    DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
+            mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
+            mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
+        }
+    }
+
+    private String getStringSetting(String which) {
+        return Settings.Global.getString(mContentResolver, which);
+    }
+
+    private int getIntSetting(String which, int dflt) {
+        return Settings.Global.getInt(mContentResolver, which, dflt);
+    }
+
+    private void setNetDnsProperty(int which, String value) {
+        final String key = "net.dns" + which;
+        // Log and forget errors setting unsupported properties.
+        try {
+            mSystemProperties.set(key, value);
+        } catch (Exception e) {
+            Slog.e(TAG, "Error setting unsupported net.dns property: ", e);
+        }
+    }
+
+    private static boolean shouldUseTls(String mode) {
+        if (TextUtils.isEmpty(mode)) {
+            mode = PRIVATE_DNS_DEFAULT_MODE;
+        }
+        return mode.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) ||
+               mode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 59870cb..ff05723 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -19,7 +19,6 @@
 import static android.hardware.usb.UsbManager.USB_CONFIGURED;
 import static android.hardware.usb.UsbManager.USB_CONNECTED;
 import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
-import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -43,7 +42,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
@@ -53,9 +51,7 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
-import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
-import android.net.NetworkRequest;
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
@@ -79,7 +75,6 @@
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -88,8 +83,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.MessageUtils;
@@ -114,12 +107,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
 
 
 /**
@@ -197,8 +186,6 @@
     private int mLastNotificationId;
 
     private boolean mRndisEnabled;       // track the RNDIS function enabled state
-    private boolean mUsbTetherRequested; // true if USB tethering should be started
-                                         // when RNDIS is enabled
     // True iff. WiFi tethering should be started when soft AP is ready.
     private boolean mWifiTetherRequested;
 
@@ -891,33 +878,18 @@
             //
             // For more explanation, see b/62552150 .
             synchronized (Tethering.this.mPublicSync) {
-                // Always record the state of RNDIS.
-                // TODO: consider:
-                //     final boolean disconnected = !usbConnected;
-                //     if (disconnected) {
-                //         mRndisEnabled = false;
-                //         mUsbTetherRequested = false;
-                //         return;
-                //     }
-                //     final boolean configured = usbConnected && usbConfigured;
-                //     mRndisEnabled = configured ? rndisEnabled : false;
-                //     if (!configured) return;
-                mRndisEnabled = rndisEnabled;
-
-                if (usbConnected && !usbConfigured) {
-                    // Nothing to do here (only CONNECTED, not yet CONFIGURED).
-                    return;
-                }
-
-                // start tethering if we have a request pending
-                if (usbConfigured && mRndisEnabled && mUsbTetherRequested) {
+                if (!usbConnected && mRndisEnabled) {
+                    // Turn off tethering if it was enabled and there is a disconnect.
+                    tetherMatchingInterfaces(
+                            IControlsTethering.STATE_AVAILABLE,
+                            ConnectivityManager.TETHERING_USB);
+                } else if (usbConfigured && rndisEnabled) {
+                    // Tether if rndis is enabled and usb is configured.
                     tetherMatchingInterfaces(
                             IControlsTethering.STATE_TETHERED,
                             ConnectivityManager.TETHERING_USB);
                 }
-
-                // TODO: Figure out how to remove the need for this variable.
-                mUsbTetherRequested = false;
+                mRndisEnabled = usbConfigured && rndisEnabled;
             }
         }
 
@@ -1121,34 +1093,8 @@
     public int setUsbTethering(boolean enable) {
         if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
         UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
-
         synchronized (mPublicSync) {
-            if (enable) {
-                if (mRndisEnabled) {
-                    final long ident = Binder.clearCallingIdentity();
-                    try {
-                        tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED,
-                                ConnectivityManager.TETHERING_USB);
-                    } finally {
-                        Binder.restoreCallingIdentity(ident);
-                    }
-                } else {
-                    mUsbTetherRequested = true;
-                    usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
-                }
-            } else {
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE,
-                            ConnectivityManager.TETHERING_USB);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-                if (mRndisEnabled) {
-                    usbManager.setCurrentFunction(null, false);
-                }
-                mUsbTetherRequested = false;
-            }
+            usbManager.setCurrentFunction(enable ? UsbManager.USB_FUNCTION_RNDIS : null, false);
         }
         return ConnectivityManager.TETHER_ERROR_NO_ERROR;
     }
@@ -1205,7 +1151,7 @@
         if (!mForwardedDownstreams.isEmpty()) return true;
 
         synchronized (mPublicSync) {
-            return mUsbTetherRequested || mWifiTetherRequested;
+            return mWifiTetherRequested;
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c7a4315..3c2d724 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -128,7 +128,7 @@
 
     // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
     // the device idle whitelist during service launch and VPN bootstrap.
-    private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION = 60 * 1000;
+    private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000;
 
     // TODO: create separate trackers for each unique VPN to support
     // automated reconnection
@@ -183,10 +183,10 @@
     @GuardedBy("this")
     private Set<UidRange> mBlockedUsers = new ArraySet<>();
 
-    // Handle of user initiating VPN.
+    // Handle of the user initiating VPN.
     private final int mUserHandle;
 
-    // Listen to package remove and change event in this user
+    // Listen to package removal and change events (update/uninstall) for this user
     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -197,14 +197,14 @@
             }
 
             synchronized (Vpn.this) {
-                // Avoid race that always-on package has been unset
+                // Avoid race where always-on package has been unset
                 if (!packageName.equals(getAlwaysOnPackage())) {
                     return;
                 }
 
                 final String action = intent.getAction();
-                Log.i(TAG, "Received broadcast " + action + " for always-on package " + packageName
-                        + " in user " + mUserHandle);
+                Log.i(TAG, "Received broadcast " + action + " for always-on VPN package "
+                        + packageName + " in user " + mUserHandle);
 
                 switch(action) {
                     case Intent.ACTION_PACKAGE_REPLACED:
@@ -248,7 +248,8 @@
             Log.wtf(TAG, "Problem registering observer", e);
         }
 
-        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
+        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
+                "" /* subtypeName */);
         mNetworkCapabilities = new NetworkCapabilities();
         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
         mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
@@ -258,7 +259,7 @@
     }
 
     /**
-     * Set if this object is responsible for watching for {@link NetworkInfo}
+     * Set whether this object is responsible for watching for {@link NetworkInfo}
      * teardown. When {@code false}, teardown is handled externally by someone
      * else.
      */
@@ -481,7 +482,6 @@
     }
 
     private void unregisterPackageChangeReceiverLocked() {
-        // register previous intent filter
         if (mIsPackageIntentReceiverRegistered) {
             mContext.unregisterReceiver(mPackageIntentReceiver);
             mIsPackageIntentReceiverRegistered = false;
@@ -582,7 +582,7 @@
             DeviceIdleController.LocalService idleController =
                     LocalServices.getService(DeviceIdleController.LocalService.class);
             idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
-                    VPN_LAUNCH_IDLE_WHITELIST_DURATION, mUserHandle, false, "vpn");
+                    VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS, mUserHandle, false, "vpn");
 
             // Start the VPN service declared in the app's manifest.
             Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
@@ -612,9 +612,10 @@
      * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and
      * it can be revoked by itself.
      *
-     * Note: when we added VPN pre-consent in http://ag/522961 the names oldPackage
-     * and newPackage become misleading, because when an app is pre-consented, we
-     * actually prepare oldPackage, not newPackage.
+     * Note: when we added VPN pre-consent in
+     * https://android.googlesource.com/platform/frameworks/base/+/0554260
+     * the names oldPackage and newPackage became misleading, because when
+     * an app is pre-consented, we actually prepare oldPackage, not newPackage.
      *
      * Their meanings actually are:
      *
@@ -630,7 +631,7 @@
      * @param oldPackage The package name of the old VPN application
      * @param newPackage The package name of the new VPN application
      *
-     * @return true if the operation is succeeded.
+     * @return true if the operation succeeded.
      */
     public synchronized boolean prepare(String oldPackage, String newPackage) {
         if (oldPackage != null) {
@@ -639,7 +640,7 @@
                 return false;
             }
 
-            // Package is not same or old package was reinstalled.
+            // Package is not the same or old package was reinstalled.
             if (!isCurrentPreparedPackage(oldPackage)) {
                 // The package doesn't match. We return false (to obtain user consent) unless the
                 // user has already consented to that VPN package.
@@ -861,8 +862,8 @@
 
         long token = Binder.clearCallingIdentity();
         try {
-            mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE,
-                    mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) {
+            mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
+                    mNetworkInfo, mNetworkCapabilities, lp, 0 /* score */, networkMisc) {
                             @Override
                             public void unwanted() {
                                 // We are user controlled, not driven by NetworkRequest.
@@ -936,7 +937,7 @@
             }
 
             ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
-                                                                        null, 0, mUserHandle);
+                    null, 0, mUserHandle);
             if (info == null) {
                 throw new SecurityException("Cannot find " + config.user);
             }
@@ -944,7 +945,7 @@
                 throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
             }
         } catch (RemoteException e) {
-                throw new SecurityException("Cannot find " + config.user);
+            throw new SecurityException("Cannot find " + config.user);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -1337,7 +1338,7 @@
     }
 
     private void enforceControlPermissionOrInternalCaller() {
-        // Require caller to be either an application with CONTROL_VPN permission or a process
+        // Require the caller to be either an application with CONTROL_VPN permission or a process
         // in the system server.
         mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN,
                 "Unauthorized Caller");
@@ -1417,7 +1418,7 @@
     }
 
     /**
-     * This method should only be called by ConnectivityService. Because it doesn't
+     * This method should only be called by ConnectivityService because it doesn't
      * have enough data to fill VpnInfo.primaryUnderlyingIface field.
      */
     public synchronized VpnInfo getVpnInfo() {
@@ -1768,7 +1769,7 @@
      * Bringing up a VPN connection takes time, and that is all this thread
      * does. Here we have plenty of time. The only thing we need to take
      * care of is responding to interruptions as soon as possible. Otherwise
-     * requests will be piled up. This can be done in a Handler as a state
+     * requests will pile up. This could be done in a Handler as a state
      * machine, but it is much easier to read in the current form.
      */
     private class LegacyVpnRunner extends Thread {
@@ -1781,7 +1782,7 @@
         private final AtomicInteger mOuterConnection =
                 new AtomicInteger(ConnectivityManager.TYPE_NONE);
 
-        private long mTimer = -1;
+        private long mBringupStartTime = -1;
 
         /**
          * Watch for the outer connection (passing in the constructor) going away.
@@ -1861,8 +1862,8 @@
             synchronized (TAG) {
                 Log.v(TAG, "Executing");
                 try {
-                    execute();
-                    monitorDaemons();
+                    bringup();
+                    waitForDaemonsToStop();
                     interrupted(); // Clear interrupt flag if execute called exit.
                 } catch (InterruptedException e) {
                 } finally {
@@ -1883,30 +1884,27 @@
             }
         }
 
-        private void checkpoint(boolean yield) throws InterruptedException {
+        private void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException {
             long now = SystemClock.elapsedRealtime();
-            if (mTimer == -1) {
-                mTimer = now;
-                Thread.sleep(1);
-            } else if (now - mTimer <= 60000) {
-                Thread.sleep(yield ? 200 : 1);
+            if (now - mBringupStartTime <= 60000) {
+                Thread.sleep(sleepLonger ? 200 : 1);
             } else {
                 updateState(DetailedState.FAILED, "checkpoint");
-                throw new IllegalStateException("Time is up");
+                throw new IllegalStateException("VPN bringup took too long");
             }
         }
 
-        private void execute() {
-            // Catch all exceptions so we can clean up few things.
+        private void bringup() {
+            // Catch all exceptions so we can clean up a few things.
             boolean initFinished = false;
             try {
                 // Initialize the timer.
-                checkpoint(false);
+                mBringupStartTime = SystemClock.elapsedRealtime();
 
                 // Wait for the daemons to stop.
                 for (String daemon : mDaemons) {
                     while (!SystemService.isStopped(daemon)) {
-                        checkpoint(true);
+                        checkInterruptAndDelay(true);
                     }
                 }
 
@@ -1943,7 +1941,7 @@
 
                     // Wait for the daemon to start.
                     while (!SystemService.isRunning(daemon)) {
-                        checkpoint(true);
+                        checkInterruptAndDelay(true);
                     }
 
                     // Create the control socket.
@@ -1959,7 +1957,7 @@
                         } catch (Exception e) {
                             // ignore
                         }
-                        checkpoint(true);
+                        checkInterruptAndDelay(true);
                     }
                     mSockets[i].setSoTimeout(500);
 
@@ -1973,7 +1971,7 @@
                         out.write(bytes.length >> 8);
                         out.write(bytes.length);
                         out.write(bytes);
-                        checkpoint(false);
+                        checkInterruptAndDelay(false);
                     }
                     out.write(0xFF);
                     out.write(0xFF);
@@ -1989,7 +1987,7 @@
                         } catch (Exception e) {
                             // ignore
                         }
-                        checkpoint(true);
+                        checkInterruptAndDelay(true);
                     }
                 }
 
@@ -2002,7 +2000,7 @@
                             throw new IllegalStateException(daemon + " is dead");
                         }
                     }
-                    checkpoint(true);
+                    checkInterruptAndDelay(true);
                 }
 
                 // Now we are connected. Read and parse the new state.
@@ -2058,8 +2056,8 @@
                     // Set the start time
                     mConfig.startTime = SystemClock.elapsedRealtime();
 
-                    // Check if the thread is interrupted while we are waiting.
-                    checkpoint(false);
+                    // Check if the thread was interrupted while we were waiting on the lock.
+                    checkInterruptAndDelay(false);
 
                     // Check if the interface is gone while we are waiting.
                     if (jniCheck(mConfig.interfaze) == 0) {
@@ -2082,10 +2080,11 @@
         }
 
         /**
-         * Monitor the daemons we started, moving to disconnected state if the
-         * underlying services fail.
+         * Check all daemons every two seconds. Return when one of them is stopped.
+         * The caller will move to the disconnected state when this function returns,
+         * which can happen if a daemon failed or if the VPN was torn down.
          */
-        private void monitorDaemons() throws InterruptedException{
+        private void waitForDaemonsToStop() throws InterruptedException {
             if (!mNetworkInfo.isConnected()) {
                 return;
             }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 17adb1a..2224913 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -30,6 +30,7 @@
 import android.net.ip.InterfaceController;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
+import android.net.util.InterfaceParams;
 import android.net.util.NetdService;
 import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
@@ -48,7 +49,6 @@
 
 import java.net.Inet6Address;
 import java.net.InetAddress;
-import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
@@ -120,8 +120,7 @@
     private int mLastError;
     private int mServingMode;
     private String mMyUpstreamIfaceName;  // may change over time
-    private NetworkInterface mNetworkInterface;
-    private byte[] mHwAddr;
+    private InterfaceParams mInterfaceParams;
     // TODO: De-duplicate this with mLinkProperties above. Currently, these link
     // properties are those selected by the IPv6TetheringCoordinator and relayed
     // to us. By comparison, mLinkProperties contains the addresses and directly
@@ -247,31 +246,16 @@
     }
 
     private boolean startIPv6() {
-        // TODO: Refactor for testability (perhaps passing an android.system.Os
-        // instance and calling getifaddrs() directly).
-        try {
-            mNetworkInterface = NetworkInterface.getByName(mIfaceName);
-        } catch (SocketException e) {
-            mLog.e("Error looking up NetworkInterfaces: " + e);
-            stopIPv6();
-            return false;
-        }
-        if (mNetworkInterface == null) {
-            mLog.e("Failed to find NetworkInterface");
+        // TODO: Refactor for better testability.  This is one of the things
+        // that prohibits unittesting IPv6 tethering setup.
+        mInterfaceParams = InterfaceParams.getByName(mIfaceName);
+        if (mInterfaceParams == null) {
+            mLog.e("Failed to find InterfaceParams");
             stopIPv6();
             return false;
         }
 
-        try {
-            mHwAddr = mNetworkInterface.getHardwareAddress();
-        } catch (SocketException e) {
-            mLog.e("Failed to find hardware address: " + e);
-            stopIPv6();
-            return false;
-        }
-
-        final int ifindex = mNetworkInterface.getIndex();
-        mRaDaemon = new RouterAdvertisementDaemon(mIfaceName, ifindex, mHwAddr);
+        mRaDaemon = new RouterAdvertisementDaemon(mInterfaceParams);
         if (!mRaDaemon.start()) {
             stopIPv6();
             return false;
@@ -281,8 +265,7 @@
     }
 
     private void stopIPv6() {
-        mNetworkInterface = null;
-        mHwAddr = null;
+        mInterfaceParams = null;
         setRaParams(null);
 
         if (mRaDaemon != null) {
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index d957ca0..51499f7 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -22,10 +22,12 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -44,6 +46,9 @@
     @GuardedBy("mLock")
     private final SparseBooleanArray mStartedSyncs = new SparseBooleanArray();
 
+    @GuardedBy("mLock")
+    private final SparseLongArray mJobStartUptimes = new SparseLongArray();
+
     private final SyncLogger mLogger = SyncLogger.getInstance();
 
     /**
@@ -82,7 +87,9 @@
         synchronized (mLock) {
             final int jobId = params.getJobId();
             mJobParamsMap.put(jobId, params);
+
             mStartedSyncs.delete(jobId);
+            mJobStartUptimes.put(jobId, SystemClock.uptimeMillis());
         }
         Message m = Message.obtain();
         m.what = SyncManager.SyncHandler.MESSAGE_START_SYNC;
@@ -113,14 +120,32 @@
             final int jobId = params.getJobId();
             mJobParamsMap.remove(jobId);
 
-            if (!mStartedSyncs.get(jobId)) {
-                final String message = "Job " + jobId + " didn't start: params=" +
-                        jobParametersToString(params);
-                mLogger.log(message);
-                Slog.wtf(TAG, message);
+            final long startUptime = mJobStartUptimes.get(jobId);
+            final long nowUptime = SystemClock.uptimeMillis();
+            final long runtime = nowUptime - startUptime;
+
+            if (startUptime == 0) {
+                wtf("Job " + jobId + " start uptime not found: "
+                        + " params=" + jobParametersToString(params));
+            } else if (runtime > 60 * 1000) {
+                // WTF if startSyncH() hasn't happened, *unless* onStopJob() was called too soon.
+                // (1 minute threshold.)
+                if (!mStartedSyncs.get(jobId)) {
+                    wtf("Job " + jobId + " didn't start: "
+                            + " startUptime=" + startUptime
+                            + " nowUptime=" + nowUptime
+                            + " params=" + jobParametersToString(params));
+                }
+            } else if (runtime < 10 * 1000) {
+                // Job stopped too soon. WTF.
+                wtf("Job " + jobId + " stopped in " + runtime + " ms: "
+                        + " startUptime=" + startUptime
+                        + " nowUptime=" + nowUptime
+                        + " params=" + jobParametersToString(params));
             }
 
             mStartedSyncs.delete(jobId);
+            mJobStartUptimes.delete(jobId);
         }
         Message m = Message.obtain();
         m.what = SyncManager.SyncHandler.MESSAGE_STOP_SYNC;
@@ -166,7 +191,13 @@
             return "job:null";
         } else {
             return "job:#" + params.getJobId() + ":"
+                    + "sr=[" + params.getStopReason() + "/" + params.getDebugStopReason() + "]:"
                     + SyncOperation.maybeCreateFromJobExtras(params.getExtras());
         }
     }
+
+    private void wtf(String message) {
+        mLogger.log(message);
+        Slog.wtf(TAG, message);
+    }
 }
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index cbb1c01..1e94e00 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -149,7 +149,7 @@
     /**
      * Start listening for brightness slider events
      *
-     * @param brightness the initial screen brightness
+     * @param initialBrightness the initial screen brightness
      */
     public void start(float initialBrightness) {
         if (DEBUG) {
@@ -219,8 +219,8 @@
                 if (includePackage) {
                     out.add(events[i]);
                 } else {
-                    BrightnessChangeEvent event = new BrightnessChangeEvent((events[i]));
-                    event.packageName = null;
+                    BrightnessChangeEvent event = new BrightnessChangeEvent((events[i]),
+                            /* redactPackage */ true);
                     out.add(event);
                 }
             }
@@ -246,7 +246,8 @@
     }
 
     private void handleBrightnessChanged(float brightness, boolean userInitiated) {
-        final BrightnessChangeEvent event;
+        BrightnessChangeEvent.Builder builder;
+
         synchronized (mDataCollectionLock) {
             if (!mStarted) {
                 // Not currently gathering brightness change information
@@ -263,9 +264,9 @@
                 return;
             }
 
-
-            event = new BrightnessChangeEvent();
-            event.timeStamp = mInjector.currentTimeMillis();
+            builder = new BrightnessChangeEvent.Builder();
+            builder.setBrightness(brightness);
+            builder.setTimeStamp(mInjector.currentTimeMillis());
 
             final int readingCount = mLastSensorReadings.size();
             if (readingCount == 0) {
@@ -273,8 +274,8 @@
                 return;
             }
 
-            event.luxValues = new float[readingCount];
-            event.luxTimestamps = new long[readingCount];
+            float[] luxValues = new float[readingCount];
+            long[] luxTimestamps = new long[readingCount];
 
             int pos = 0;
 
@@ -282,33 +283,35 @@
             long currentTimeMillis = mInjector.currentTimeMillis();
             long elapsedTimeNanos = mInjector.elapsedRealtimeNanos();
             for (LightData reading : mLastSensorReadings) {
-                event.luxValues[pos] = reading.lux;
-                event.luxTimestamps[pos] = currentTimeMillis -
+                luxValues[pos] = reading.lux;
+                luxTimestamps[pos] = currentTimeMillis -
                         TimeUnit.NANOSECONDS.toMillis(elapsedTimeNanos - reading.timestamp);
                 ++pos;
             }
+            builder.setLuxValues(luxValues);
+            builder.setLuxTimestamps(luxTimestamps);
 
-            event.batteryLevel = mLastBatteryLevel;
-            event.lastBrightness = previousBrightness;
+            builder.setBatteryLevel(mLastBatteryLevel);
+            builder.setLastBrightness(previousBrightness);
         }
 
-        event.brightness = brightness;
-
         try {
             final ActivityManager.StackInfo focusedStack = mInjector.getFocusedStack();
-            event.userId = focusedStack.userId;
-            event.packageName = focusedStack.topActivity.getPackageName();
+            builder.setUserId(focusedStack.userId);
+            builder.setPackageName(focusedStack.topActivity.getPackageName());
         } catch (RemoteException e) {
             // Really shouldn't be possible.
+            return;
         }
 
-        event.nightMode = mInjector.getSecureIntForUser(mContentResolver,
+        builder.setNightMode(mInjector.getSecureIntForUser(mContentResolver,
                 Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 0, UserHandle.USER_CURRENT)
-                == 1;
-        event.colorTemperature = mInjector.getSecureIntForUser(mContentResolver,
+                == 1);
+        builder.setColorTemperature(mInjector.getSecureIntForUser(mContentResolver,
                 Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
-                0, UserHandle.USER_CURRENT);
+                0, UserHandle.USER_CURRENT));
 
+        BrightnessChangeEvent event = builder.build();
         if (DEBUG) {
             Slog.d(TAG, "Event " + event.brightness + " " + event.packageName);
         }
@@ -457,40 +460,43 @@
                 }
                 tag = parser.getName();
                 if (TAG_EVENT.equals(tag)) {
-                    BrightnessChangeEvent event = new BrightnessChangeEvent();
+                    BrightnessChangeEvent.Builder builder = new BrightnessChangeEvent.Builder();
 
                     String brightness = parser.getAttributeValue(null, ATTR_NITS);
-                    event.brightness = Float.parseFloat(brightness);
+                    builder.setBrightness(Float.parseFloat(brightness));
                     String timestamp = parser.getAttributeValue(null, ATTR_TIMESTAMP);
-                    event.timeStamp = Long.parseLong(timestamp);
-                    event.packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                    builder.setTimeStamp(Long.parseLong(timestamp));
+                    builder.setPackageName(parser.getAttributeValue(null, ATTR_PACKAGE_NAME));
                     String user = parser.getAttributeValue(null, ATTR_USER);
-                    event.userId = mInjector.getUserId(mUserManager, Integer.parseInt(user));
+                    builder.setUserId(mInjector.getUserId(mUserManager, Integer.parseInt(user)));
                     String batteryLevel = parser.getAttributeValue(null, ATTR_BATTERY_LEVEL);
-                    event.batteryLevel = Float.parseFloat(batteryLevel);
+                    builder.setBatteryLevel(Float.parseFloat(batteryLevel));
                     String nightMode = parser.getAttributeValue(null, ATTR_NIGHT_MODE);
-                    event.nightMode = Boolean.parseBoolean(nightMode);
+                    builder.setNightMode(Boolean.parseBoolean(nightMode));
                     String colorTemperature =
                             parser.getAttributeValue(null, ATTR_COLOR_TEMPERATURE);
-                    event.colorTemperature = Integer.parseInt(colorTemperature);
+                    builder.setColorTemperature(Integer.parseInt(colorTemperature));
                     String lastBrightness = parser.getAttributeValue(null, ATTR_LAST_NITS);
-                    event.lastBrightness = Float.parseFloat(lastBrightness);
+                    builder.setLastBrightness(Float.parseFloat(lastBrightness));
 
                     String luxValue = parser.getAttributeValue(null, ATTR_LUX);
                     String luxTimestamp = parser.getAttributeValue(null, ATTR_LUX_TIMESTAMPS);
 
-                    String[] luxValues = luxValue.split(",");
-                    String[] luxTimestamps = luxTimestamp.split(",");
-                    if (luxValues.length != luxTimestamps.length) {
+                    String[] luxValuesStrings = luxValue.split(",");
+                    String[] luxTimestampsStrings = luxTimestamp.split(",");
+                    if (luxValuesStrings.length != luxTimestampsStrings.length) {
                         continue;
                     }
-                    event.luxValues = new float[luxValues.length];
-                    event.luxTimestamps = new long[luxValues.length];
+                    float[] luxValues = new float[luxValuesStrings.length];
+                    long[] luxTimestamps = new long[luxValuesStrings.length];
                     for (int i = 0; i < luxValues.length; ++i) {
-                        event.luxValues[i] = Float.parseFloat(luxValues[i]);
-                        event.luxTimestamps[i] = Long.parseLong(luxTimestamps[i]);
+                        luxValues[i] = Float.parseFloat(luxValuesStrings[i]);
+                        luxTimestamps[i] = Long.parseLong(luxTimestampsStrings[i]);
                     }
+                    builder.setLuxValues(luxValues);
+                    builder.setLuxTimestamps(luxTimestamps);
 
+                    BrightnessChangeEvent event = builder.build();
                     if (DEBUG) {
                         Slog.i(TAG, "Read event " + event.brightness
                                 + " " + event.packageName);
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 85686ae..4f53ed4 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -99,7 +99,7 @@
     private final float mProjMatrix[] = new float[16];
     private final int[] mGLBuffers = new int[2];
     private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
-    private int mOpacityLoc, mGammaLoc, mSaturationLoc;
+    private int mOpacityLoc, mGammaLoc;
     private int mProgram;
 
     // Vertex and corresponding texture coordinates.
@@ -245,7 +245,6 @@
 
         mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
         mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
-        mSaturationLoc = GLES20.glGetUniformLocation(mProgram, "saturation");
         mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
 
         GLES20.glUseProgram(mProgram);
@@ -393,9 +392,8 @@
             double cos = Math.cos(Math.PI * one_minus_level);
             double sign = cos < 0 ? -1 : 1;
             float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
-            float saturation = (float) Math.pow(level, 4);
             float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
-            drawFaded(opacity, 1.f / gamma, saturation);
+            drawFaded(opacity, 1.f / gamma);
             if (checkGlErrors("drawFrame")) {
                 return false;
             }
@@ -407,10 +405,9 @@
         return showSurface(1.0f);
     }
 
-    private void drawFaded(float opacity, float gamma, float saturation) {
+    private void drawFaded(float opacity, float gamma) {
         if (DEBUG) {
-            Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma +
-                        ", saturation=" + saturation);
+            Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma);
         }
         // Use shaders
         GLES20.glUseProgram(mProgram);
@@ -420,7 +417,6 @@
         GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
         GLES20.glUniform1f(mOpacityLoc, opacity);
         GLES20.glUniform1f(mGammaLoc, gamma);
-        GLES20.glUniform1f(mSaturationLoc, saturation);
 
         // Use textures
         GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index fddb81b..6db3b44 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -19,6 +19,7 @@
 import android.hardware.display.DisplayViewport;
 import android.util.DisplayMetrics;
 import android.view.Display;
+import android.view.DisplayCutout;
 import android.view.Surface;
 
 import java.util.Arrays;
@@ -229,6 +230,11 @@
     public int flags;
 
     /**
+     * The {@link DisplayCutout} if present or {@code null} otherwise.
+     */
+    public DisplayCutout displayCutout;
+
+    /**
      * The touch attachment, per {@link DisplayViewport#touch}.
      */
     public int touch;
@@ -321,6 +327,7 @@
                 || appVsyncOffsetNanos != other.appVsyncOffsetNanos
                 || presentationDeadlineNanos != other.presentationDeadlineNanos
                 || flags != other.flags
+                || !Objects.equal(displayCutout, other.displayCutout)
                 || touch != other.touch
                 || rotation != other.rotation
                 || type != other.type
@@ -354,6 +361,7 @@
         appVsyncOffsetNanos = other.appVsyncOffsetNanos;
         presentationDeadlineNanos = other.presentationDeadlineNanos;
         flags = other.flags;
+        displayCutout = other.displayCutout;
         touch = other.touch;
         rotation = other.rotation;
         type = other.type;
@@ -380,6 +388,9 @@
         sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi");
         sb.append(", appVsyncOff ").append(appVsyncOffsetNanos);
         sb.append(", presDeadline ").append(presentationDeadlineNanos);
+        if (displayCutout != null) {
+            sb.append(", cutout ").append(displayCutout);
+        }
         sb.append(", touch ").append(touchToString(touch));
         sb.append(", rotation ").append(rotation);
         sb.append(", type ").append(Display.typeToString(type));
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index eb9ff58..23e4c9b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import android.app.ActivityThread;
 import android.content.res.Resources;
 import com.android.server.LocalServices;
 import com.android.server.lights.Light;
@@ -30,9 +31,12 @@
 import android.os.PowerManager;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.text.TextUtils;
+import android.util.PathParser;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.DisplayCutout;
 import android.view.DisplayEventReceiver;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -389,7 +393,7 @@
                             | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
                 }
 
-                final Resources res = getContext().getResources();
+                final Resources res = getOverlayContext().getResources();
                 if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
                     mInfo.name = res.getString(
                             com.android.internal.R.string.display_manager_built_in_display_name);
@@ -400,12 +404,14 @@
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
+                    mInfo.displayCutout = parseDefaultDisplayCutout(res);
                     mInfo.type = Display.TYPE_BUILT_IN;
                     mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
                     mInfo.xDpi = phys.xDpi;
                     mInfo.yDpi = phys.yDpi;
                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
                 } else {
+                    mInfo.displayCutout = null;
                     mInfo.type = Display.TYPE_HDMI;
                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
                     mInfo.name = getContext().getResources().getString(
@@ -434,6 +440,15 @@
             return mInfo;
         }
 
+        private DisplayCutout parseDefaultDisplayCutout(Resources res) {
+            String cutoutString = res.getString(
+                    com.android.internal.R.string.config_mainBuiltInDisplayCutout);
+            if (TextUtils.isEmpty(cutoutString)) {
+                return null;
+            }
+            return DisplayCutout.fromBounds(PathParser.createPathFromPathData(cutoutString));
+        }
+
         @Override
         public Runnable requestDisplayStateLocked(final int state, final int brightness) {
             // Assume that the brightness is off if the display is being turned off.
@@ -673,6 +688,11 @@
         }
     }
 
+    /** Supplies a context whose Resources apply runtime-overlays */
+    Context getOverlayContext() {
+        return ActivityThread.currentActivityThread().getSystemUiContext();
+    }
+
     /**
      * Keeps track of a display configuration.
      */
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 78a5407..132f083 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -145,6 +145,7 @@
                 mInfo.overscanRight = mOverrideDisplayInfo.overscanRight;
                 mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
                 mInfo.rotation = mOverrideDisplayInfo.rotation;
+                mInfo.displayCutout = mOverrideDisplayInfo.displayCutout;
                 mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
                 mInfo.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
                 mInfo.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
@@ -280,6 +281,7 @@
             mBaseDisplayInfo.largestNominalAppHeight = deviceInfo.height;
             mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid;
             mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName;
+            mBaseDisplayInfo.displayCutout = deviceInfo.displayCutout;
 
             mPrimaryDisplayDeviceInfo = deviceInfo;
             mInfo = null;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 987baf9..bd1dbf9 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -934,12 +934,14 @@
      * @param uid Uid of the calling client.
      * @param jobId Id of the job, provided at schedule-time.
      */
-    public boolean cancelJob(int uid, int jobId) {
+    public boolean cancelJob(int uid, int jobId, int callingUid) {
         JobStatus toCancel;
         synchronized (mLock) {
             toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
             if (toCancel != null) {
-                cancelJobImplLocked(toCancel, null, "cancel() called by app");
+                cancelJobImplLocked(toCancel, null,
+                        "cancel() called by app, callingUid=" + callingUid
+                        + " uid=" + uid + " jobId=" + jobId);
             }
             return (toCancel != null);
         }
@@ -965,7 +967,7 @@
                 // with just the foreground priority.  This means that persistent processes
                 // can never be the top app priority...  that is fine.
                 mUidPriorityOverride.put(uid, JobInfo.PRIORITY_TOP_APP);
-            } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+            } else if (procState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
                 mUidPriorityOverride.put(uid, JobInfo.PRIORITY_FOREGROUND_APP);
             } else {
                 mUidPriorityOverride.delete(uid);
@@ -2341,7 +2343,8 @@
             final int uid = Binder.getCallingUid();
             long ident = Binder.clearCallingIdentity();
             try {
-                JobSchedulerService.this.cancelJobsForUid(uid, "cancelAll() called by app");
+                JobSchedulerService.this.cancelJobsForUid(uid,
+                        "cancelAll() called by app, callingUid=" + uid);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -2353,7 +2356,7 @@
 
             long ident = Binder.clearCallingIdentity();
             try {
-                JobSchedulerService.this.cancelJob(uid, jobId);
+                JobSchedulerService.this.cancelJob(uid, jobId, uid);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -2466,7 +2469,7 @@
             for (int i=0; i<mActiveServices.size(); i++) {
                 final JobServiceContext jc = mActiveServices.get(i);
                 final JobStatus js = jc.getRunningJobLocked();
-                if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId)) {
+                if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
                     foundSome = true;
                     pw.print("Timing out: ");
                     js.printUniqueId(pw);
@@ -2506,7 +2509,7 @@
             }
         } else {
             pw.println("Canceling job " + pkgName + "/#" + jobId + " in user " + userId);
-            if (!cancelJob(pkgUid, jobId)) {
+            if (!cancelJob(pkgUid, jobId, Process.SHELL_UID)) {
                 pw.println("No matching job found.");
             }
         }
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 709deeb..83a3c19 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -312,13 +312,14 @@
         return mTimeoutElapsed;
     }
 
-    boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId) {
+    boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId,
+            String reason) {
         final JobStatus executing = getRunningJobLocked();
         if (executing != null && (userId == UserHandle.USER_ALL || userId == executing.getUserId())
                 && (pkgName == null || pkgName.equals(executing.getSourcePackageName()))
                 && (!matchJobId || jobId == executing.getJobId())) {
             if (mVerb == VERB_EXECUTING) {
-                mParams.setStopReason(JobParameters.REASON_TIMEOUT);
+                mParams.setStopReason(JobParameters.REASON_TIMEOUT, reason);
                 sendStopMessageLocked("force timeout from shell");
                 return true;
             }
@@ -537,7 +538,7 @@
             }
             return;
         }
-        mParams.setStopReason(arg1);
+        mParams.setStopReason(arg1, debugReason);
         if (arg1 == JobParameters.REASON_PREEMPT) {
             mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
                     NO_PREFERRED_UID;
@@ -687,7 +688,7 @@
                 // Not an error - client ran out of time.
                 Slog.i(TAG, "Client timed out while executing (no jobFinished received), " +
                         "sending onStop: " + getRunningJobNameLocked());
-                mParams.setStopReason(JobParameters.REASON_TIMEOUT);
+                mParams.setStopReason(JobParameters.REASON_TIMEOUT, "client timed out");
                 sendStopMessageLocked("timeout while executing");
                 break;
             default:
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index e6de07d..e158819 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -84,8 +84,6 @@
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
 
-import com.android.server.power.BatterySaverPolicy;
-
 import libcore.io.IoUtils;
 
 import java.io.File;
@@ -579,7 +577,7 @@
         final PowerSaveState result =
                 mPowerManager.getPowerSaveState(ServiceType.GPS);
         switch (result.gpsMode) {
-            case BatterySaverPolicy.GPS_MODE_DISABLED_WHEN_SCREEN_OFF:
+            case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
                 // If we are in battery saver mode and the screen is off, disable GPS.
                 disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive();
                 break;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 516828b..ee08c38 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -79,10 +79,10 @@
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
 import android.security.keystore.UserNotAuthenticatedException;
-import android.security.recoverablekeystore.KeyEntryRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryMetadata;
-import android.security.recoverablekeystore.RecoverableKeyStoreLoader.RecoverableKeyStoreLoaderException;
+import android.security.keystore.EntryRecoveryData;
+import android.security.keystore.RecoveryData;
+import android.security.keystore.RecoveryMetadata;
+import android.security.keystore.RecoveryManagerException;
 import android.service.gatekeeper.GateKeeperResponse;
 import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
@@ -1968,7 +1968,7 @@
     }
 
     @Override
-    public KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account) throws RemoteException {
+    public RecoveryData getRecoveryData(@NonNull byte[] account) throws RemoteException {
         return mRecoverableKeyStoreManager.getRecoveryData(account);
     }
 
@@ -1982,8 +1982,8 @@
     }
 
     @Override
-    public void setServerParameters(long serverParameters) throws RemoteException {
-        mRecoverableKeyStoreManager.setServerParameters(serverParameters);
+    public void setServerParams(byte[] serverParams) throws RemoteException {
+        mRecoverableKeyStoreManager.setServerParams(serverParams);
     }
 
     @Override
@@ -1997,7 +1997,7 @@
     }
 
     @Override
-    public void setRecoverySecretTypes(@NonNull @KeyStoreRecoveryMetadata.UserSecretType
+    public void setRecoverySecretTypes(@NonNull @RecoveryMetadata.UserSecretType
             int[] secretTypes) throws RemoteException {
         mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
     }
@@ -2014,7 +2014,7 @@
     }
 
     @Override
-    public void recoverySecretAvailable(@NonNull KeyStoreRecoveryMetadata recoverySecret)
+    public void recoverySecretAvailable(@NonNull RecoveryMetadata recoverySecret)
             throws RemoteException {
         mRecoverableKeyStoreManager.recoverySecretAvailable(recoverySecret);
     }
@@ -2022,7 +2022,7 @@
     @Override
     public byte[] startRecoverySession(@NonNull String sessionId,
             @NonNull byte[] verifierPublicKey, @NonNull byte[] vaultParams,
-            @NonNull byte[] vaultChallenge, @NonNull List<KeyStoreRecoveryMetadata> secrets)
+            @NonNull byte[] vaultChallenge, @NonNull List<RecoveryMetadata> secrets)
             throws RemoteException {
         return mRecoverableKeyStoreManager.startRecoverySession(sessionId, verifierPublicKey,
                 vaultParams, vaultChallenge, secrets);
@@ -2030,7 +2030,7 @@
 
     @Override
     public Map<String, byte[]> recoverKeys(@NonNull String sessionId,
-            @NonNull byte[] recoveryKeyBlob, @NonNull List<KeyEntryRecoveryData> applicationKeys)
+            @NonNull byte[] recoveryKeyBlob, @NonNull List<EntryRecoveryData> applicationKeys)
             throws RemoteException {
         return mRecoverableKeyStoreManager.recoverKeys(
                 sessionId, recoveryKeyBlob, applicationKeys);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index e028fef..5fe11b1 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -16,17 +16,19 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import static android.security.recoverablekeystore.KeyStoreRecoveryMetadata.TYPE_LOCKSCREEN;
+import static android.security.keystore.RecoveryMetadata.TYPE_LOCKSCREEN;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
-import android.security.recoverablekeystore.KeyDerivationParameters;
-import android.security.recoverablekeystore.KeyEntryRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryMetadata;
+import android.security.keystore.KeyDerivationParams;
+import android.security.keystore.EntryRecoveryData;
+import android.security.keystore.RecoveryData;
+import android.security.keystore.RecoveryMetadata;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
@@ -100,7 +102,7 @@
      *
      * @param recoverableKeyStoreDb Database where the keys are stored.
      * @param userId The uid of the user whose profile has been unlocked.
-     * @param credentialType The type of credential - i.e., pattern or password.
+     * @param credentialType The type of credential as defined in {@code LockPatternUtils}
      * @param credential The credential, encoded as a {@link String}.
      * @param credentialUpdated signals weather credentials were updated.
      * @param platformKeyManagerFactory Instantiates a {@link PlatformKeyManager} for the user.
@@ -173,7 +175,7 @@
             return;
         }
 
-        Long deviceId = mRecoverableKeyStoreDb.getServerParameters(mUserId, recoveryAgentUid);
+        byte[] deviceId = mRecoverableKeyStoreDb.getServerParams(mUserId, recoveryAgentUid);
         if (deviceId == null) {
             Log.w(TAG, "No device ID set for user " + mUserId);
             return;
@@ -230,8 +232,8 @@
         byte[] vaultParams = KeySyncUtils.packVaultParams(
                 publicKey,
                 counterId,
-                TRUSTED_HARDWARE_MAX_ATTEMPTS,
-                deviceId);
+                deviceId,
+                TRUSTED_HARDWARE_MAX_ATTEMPTS);
 
         byte[] encryptedRecoveryKey;
         try {
@@ -248,12 +250,13 @@
             return;
         }
         // TODO: store raw data in RecoveryServiceMetadataEntry and generate Parcelables later
-        KeyStoreRecoveryMetadata metadata = new KeyStoreRecoveryMetadata(
+        // TODO: use Builder.
+        RecoveryMetadata metadata = new RecoveryMetadata(
                 /*userSecretType=*/ TYPE_LOCKSCREEN,
-                /*lockScreenUiFormat=*/ mCredentialType,
-                /*keyDerivationParameters=*/ KeyDerivationParameters.createSha256Parameters(salt),
+                /*lockScreenUiFormat=*/ getUiFormat(mCredentialType, mCredential),
+                /*keyDerivationParams=*/ KeyDerivationParams.createSha256Params(salt),
                 /*secret=*/ new byte[0]);
-        ArrayList<KeyStoreRecoveryMetadata> metadataList = new ArrayList<>();
+        ArrayList<RecoveryMetadata> metadataList = new ArrayList<>();
         metadataList.add(metadata);
 
         int snapshotVersion = incrementSnapshotVersion(recoveryAgentUid);
@@ -261,7 +264,8 @@
         // If application keys are not updated, snapshot will not be created on next unlock.
         mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false);
 
-        mRecoverySnapshotStorage.put(recoveryAgentUid, new KeyStoreRecoveryData(
+        // TODO: use Builder.
+        mRecoverySnapshotStorage.put(recoveryAgentUid, new RecoveryData(
                 snapshotVersion,
                 /*recoveryMetadata=*/ metadataList,
                 /*applicationKeyBlobs=*/ createApplicationKeyEntries(encryptedApplicationKeys),
@@ -303,6 +307,12 @@
      * @param recoveryAgentUid uid of the recovery agent.
      */
     private boolean shoudCreateSnapshot(int recoveryAgentUid) {
+        int[] types = mRecoverableKeyStoreDb.getRecoverySecretTypes(mUserId, recoveryAgentUid);
+        if (!ArrayUtils.contains(types, RecoveryMetadata.TYPE_LOCKSCREEN)) {
+            // Only lockscreen type is supported.
+            // We will need to pass extra argument to KeySyncTask to support custom pass phrase.
+            return false;
+        }
         if (mCredentialUpdated) {
             // Sync credential if at least one snapshot was created.
             if (mRecoverableKeyStoreDb.getSnapshotVersion(mUserId, recoveryAgentUid) != null) {
@@ -321,14 +331,14 @@
      * @return The format - either pattern, pin, or password.
      */
     @VisibleForTesting
-    @KeyStoreRecoveryMetadata.LockScreenUiFormat static int getUiFormat(
+    @RecoveryMetadata.LockScreenUiFormat static int getUiFormat(
             int credentialType, String credential) {
         if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
-            return KeyStoreRecoveryMetadata.TYPE_PATTERN;
+            return RecoveryMetadata.TYPE_PATTERN;
         } else if (isPin(credential)) {
-            return KeyStoreRecoveryMetadata.TYPE_PIN;
+            return RecoveryMetadata.TYPE_PIN;
         } else {
-            return KeyStoreRecoveryMetadata.TYPE_PASSWORD;
+            return RecoveryMetadata.TYPE_PASSWORD;
         }
     }
 
@@ -347,7 +357,10 @@
      * Returns {@code true} if {@code credential} looks like a pin.
      */
     @VisibleForTesting
-    static boolean isPin(@NonNull String credential) {
+    static boolean isPin(@Nullable String credential) {
+        if (credential == null) {
+            return false;
+        }
         int length = credential.length();
         for (int i = 0; i < length; i++) {
             if (!Character.isDigit(credential.charAt(i))) {
@@ -388,12 +401,12 @@
         return keyGenerator.generateKey();
     }
 
-    private static List<KeyEntryRecoveryData> createApplicationKeyEntries(
+    private static List<EntryRecoveryData> createApplicationKeyEntries(
             Map<String, byte[]> encryptedApplicationKeys) {
-        ArrayList<KeyEntryRecoveryData> keyEntries = new ArrayList<>();
+        ArrayList<EntryRecoveryData> keyEntries = new ArrayList<>();
         for (String alias : encryptedApplicationKeys.keySet()) {
             keyEntries.add(
-                    new KeyEntryRecoveryData(
+                    new EntryRecoveryData(
                             alias,
                             encryptedApplicationKeys.get(alias)));
         }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
index e851d8c..b4bef17 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
@@ -37,8 +37,7 @@
 import javax.crypto.SecretKey;
 
 /**
- * Utility functions for the flow where the RecoverableKeyStoreLoader syncs keys with remote
- * storage.
+ * Utility functions for the flow where the RecoveryManager syncs keys with remote storage.
  *
  * @hide
  */
@@ -288,17 +287,17 @@
      *
      * @param thmPublicKey Public key of the trusted hardware module.
      * @param counterId ID referring to the specific counter in the hardware module.
-     * @param maxAttempts Maximum allowed guesses before trusted hardware wipes key.
      * @param deviceId ID of the device.
+     * @param maxAttempts Maximum allowed guesses before trusted hardware wipes key.
      * @return The binary vault params, ready for sync.
      */
     public static byte[] packVaultParams(
-            PublicKey thmPublicKey, long counterId, int maxAttempts, long deviceId) {
+            PublicKey thmPublicKey, long counterId, byte[] deviceId, int maxAttempts) {
         return ByteBuffer.allocate(VAULT_PARAMS_LENGTH_BYTES)
                 .order(ByteOrder.LITTLE_ENDIAN)
                 .put(SecureBox.encodePublicKey(thmPublicKey))
                 .putLong(counterId)
-                .putLong(deviceId)
+                .putLong(0L) // TODO: replace with device Id.
                 .putInt(maxAttempts)
                 .array();
     }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index a6f7766..7658178 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -16,32 +16,28 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import static android.security.recoverablekeystore.RecoverableKeyStoreLoader
-        .ERROR_BAD_X509_CERTIFICATE;
-import static android.security.recoverablekeystore.RecoverableKeyStoreLoader.ERROR_DATABASE_ERROR;
-import static android.security.recoverablekeystore.RecoverableKeyStoreLoader
-        .ERROR_DECRYPTION_FAILED;
-import static android.security.recoverablekeystore.RecoverableKeyStoreLoader.ERROR_INSECURE_USER;
-import static android.security.recoverablekeystore.RecoverableKeyStoreLoader
-        .ERROR_KEYSTORE_INTERNAL_ERROR;
-import static android.security.recoverablekeystore.RecoverableKeyStoreLoader
-        .ERROR_NOT_YET_SUPPORTED;
-import static android.security.recoverablekeystore.RecoverableKeyStoreLoader
-        .ERROR_UNEXPECTED_MISSING_ALGORITHM;
+import static android.security.keystore.RecoveryManagerException.ERROR_BAD_X509_CERTIFICATE;
+import static android.security.keystore.RecoveryManagerException.ERROR_DATABASE_ERROR;
+import static android.security.keystore.RecoveryManagerException.ERROR_DECRYPTION_FAILED;
+import static android.security.keystore.RecoveryManagerException.ERROR_INSECURE_USER;
+import static android.security.keystore.RecoveryManagerException.ERROR_KEYSTORE_INTERNAL_ERROR;
+import static android.security.keystore.RecoveryManagerException.ERROR_UNEXPECTED_MISSING_ALGORITHM;
+import static android.security.keystore.RecoveryManagerException.ERROR_NO_SNAPSHOT_PENDING;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.Manifest;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 
-import android.security.recoverablekeystore.KeyEntryRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryMetadata;
-import android.security.recoverablekeystore.RecoverableKeyStoreLoader;
+import android.security.keystore.EntryRecoveryData;
+import android.security.keystore.RecoveryData;
+import android.security.keystore.RecoveryMetadata;
+import android.security.keystore.RecoveryManager;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -69,7 +65,7 @@
 import javax.crypto.AEADBadTagException;
 
 /**
- * Class with {@link RecoverableKeyStoreLoader} API implementation and internal methods to interact
+ * Class with {@link RecoveryManager} API implementation and internal methods to interact
  * with {@code LockSettingsService}.
  *
  * @hide
@@ -148,6 +144,7 @@
             throws RemoteException {
         checkRecoverKeyStorePermission();
         int userId = UserHandle.getCallingUserId();
+        int uid = Binder.getCallingUid();
         // TODO: open /system/etc/security/... cert file, and check the signature on the public keys
         PublicKey publicKey;
         try {
@@ -162,7 +159,10 @@
             throw new ServiceSpecificException(
                     ERROR_BAD_X509_CERTIFICATE, "Not a valid X509 certificate.");
         }
-        mDatabase.setRecoveryServicePublicKey(userId, Binder.getCallingUid(), publicKey);
+        long updatedRows = mDatabase.setRecoveryServicePublicKey(userId, uid, publicKey);
+        if (updatedRows > 0) {
+            mDatabase.setShouldCreateSnapshot(userId, uid, true);
+        }
     }
 
     /**
@@ -171,13 +171,13 @@
      * @return recovery data
      * @hide
      */
-    public @NonNull KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account)
+    public @NonNull RecoveryData getRecoveryData(@NonNull byte[] account)
             throws RemoteException {
         checkRecoverKeyStorePermission();
         int uid = Binder.getCallingUid();
-        KeyStoreRecoveryData snapshot = mSnapshotStorage.get(uid);
+        RecoveryData snapshot = mSnapshotStorage.get(uid);
         if (snapshot == null) {
-            throw new ServiceSpecificException(RecoverableKeyStoreLoader.ERROR_NO_SNAPSHOT_PENDING);
+            throw new ServiceSpecificException(ERROR_NO_SNAPSHOT_PENDING);
         }
         return snapshot;
     }
@@ -201,10 +201,14 @@
         throw new UnsupportedOperationException();
     }
 
-    public void setServerParameters(long serverParameters) throws RemoteException {
+    public void setServerParams(byte[] serverParams) throws RemoteException {
         checkRecoverKeyStorePermission();
         int userId = UserHandle.getCallingUserId();
-        mDatabase.setServerParameters(userId, Binder.getCallingUid(), serverParameters);
+        int uid = Binder.getCallingUid();
+        long updatedRows = mDatabase.setServerParams(userId, uid, serverParams);
+        if (updatedRows > 0) {
+            mDatabase.setShouldCreateSnapshot(userId, uid, true);
+        }
     }
 
     /**
@@ -253,11 +257,15 @@
      * @hide
      */
     public void setRecoverySecretTypes(
-            @NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] secretTypes)
+            @NonNull @RecoveryMetadata.UserSecretType int[] secretTypes)
             throws RemoteException {
         checkRecoverKeyStorePermission();
-        mDatabase.setRecoverySecretTypes(UserHandle.getCallingUserId(), Binder.getCallingUid(),
-            secretTypes);
+        int userId = UserHandle.getCallingUserId();
+        int uid = Binder.getCallingUid();
+        long updatedRows = mDatabase.setRecoverySecretTypes(userId, uid, secretTypes);
+        if (updatedRows > 0) {
+            mDatabase.setShouldCreateSnapshot(userId, uid, true);
+        }
     }
 
     /**
@@ -273,7 +281,7 @@
     }
 
     /**
-     * Gets secret types RecoverableKeyStoreLoaders is waiting for to create new Recovery Data.
+     * Gets secret types RecoveryManagers is waiting for to create new Recovery Data.
      *
      * @return secret types
      * @hide
@@ -284,9 +292,9 @@
     }
 
     public void recoverySecretAvailable(
-            @NonNull KeyStoreRecoveryMetadata recoverySecret) throws RemoteException {
+            @NonNull RecoveryMetadata recoverySecret) throws RemoteException {
         int uid = Binder.getCallingUid();
-        if (recoverySecret.getLockScreenUiFormat() == KeyStoreRecoveryMetadata.TYPE_LOCKSCREEN) {
+        if (recoverySecret.getLockScreenUiFormat() == RecoveryMetadata.TYPE_LOCKSCREEN) {
             throw new SecurityException(
                     "Caller " + uid + " is not allowed to set lock screen secret");
         }
@@ -312,16 +320,13 @@
             @NonNull byte[] verifierPublicKey,
             @NonNull byte[] vaultParams,
             @NonNull byte[] vaultChallenge,
-            @NonNull List<KeyStoreRecoveryMetadata> secrets)
+            @NonNull List<RecoveryMetadata> secrets)
             throws RemoteException {
         checkRecoverKeyStorePermission();
         int uid = Binder.getCallingUid();
 
         if (secrets.size() != 1) {
-            // TODO: support multiple secrets
-            throw new ServiceSpecificException(
-                    ERROR_NOT_YET_SUPPORTED,
-                    "Only a single KeyStoreRecoveryMetadata is supported");
+            throw new UnsupportedOperationException("Only a single RecoveryMetadata is supported");
         }
 
         PublicKey publicKey;
@@ -379,7 +384,7 @@
     public Map<String, byte[]> recoverKeys(
             @NonNull String sessionId,
             @NonNull byte[] encryptedRecoveryKey,
-            @NonNull List<KeyEntryRecoveryData> applicationKeys)
+            @NonNull List<EntryRecoveryData> applicationKeys)
             throws RemoteException {
         checkRecoverKeyStorePermission();
         int uid = Binder.getCallingUid();
@@ -469,9 +474,9 @@
      */
     private Map<String, byte[]> recoverApplicationKeys(
             @NonNull byte[] recoveryKey,
-            @NonNull List<KeyEntryRecoveryData> applicationKeys) throws RemoteException {
+            @NonNull List<EntryRecoveryData> applicationKeys) throws RemoteException {
         HashMap<String, byte[]> keyMaterialByAlias = new HashMap<>();
-        for (KeyEntryRecoveryData applicationKey : applicationKeys) {
+        for (EntryRecoveryData applicationKey : applicationKeys) {
             String alias = applicationKey.getAlias();
             byte[] encryptedKeyMaterial = applicationKey.getEncryptedKeyMaterial();
 
@@ -555,7 +560,7 @@
 
     private void checkRecoverKeyStorePermission() {
         mContext.enforceCallingOrSelfPermission(
-                RecoverableKeyStoreLoader.PERMISSION_RECOVER_KEYSTORE,
+                Manifest.permission.RECOVER_KEYSTORE,
                 "Caller " + Binder.getCallingUid() + " doesn't have RecoverKeyStore permission.");
     }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
index 54aa9f0..0042e10 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
@@ -17,7 +17,7 @@
 package com.android.server.locksettings.recoverablekeystore;
 
 import android.util.Log;
-import android.security.recoverablekeystore.RecoverableKeyStoreLoader;
+import android.security.keystore.RecoveryManager;
 
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -97,7 +97,7 @@
                 /*nonce=*/ cipher.getIV(),
                 /*keyMaterial=*/ encryptedKeyMaterial,
                 /*platformKeyGenerationId=*/ wrappingKey.getGenerationId(),
-                RecoverableKeyStoreLoader.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+                RecoveryManager.RECOVERY_STATUS_SYNC_IN_PROGRESS);
     }
 
     /**
@@ -107,14 +107,14 @@
      * @param keyMaterial The encrypted bytes of the key material.
      * @param platformKeyGenerationId The generation ID of the key used to wrap this key.
      *
-     * @see RecoverableKeyStoreLoader.RECOVERY_STATUS_SYNC_IN_PROGRESS
+     * @see RecoveryManager.RECOVERY_STATUS_SYNC_IN_PROGRESS
      * @hide
      */
     public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId) {
         mNonce = nonce;
         mKeyMaterial = keyMaterial;
         mPlatformKeyGenerationId = platformKeyGenerationId;
-        mRecoveryStatus = RecoverableKeyStoreLoader.RECOVERY_STATUS_SYNC_IN_PROGRESS;
+        mRecoveryStatus = RecoveryManager.RECOVERY_STATUS_SYNC_IN_PROGRESS;
     }
 
     /**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index c6f3ede..eb2da80 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -336,17 +336,8 @@
      * @hide
      */
     public long setRecoveryServicePublicKey(int userId, int uid, PublicKey publicKey) {
-        SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
-        ContentValues values = new ContentValues();
-        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY, publicKey.getEncoded());
-        String selection =
-                RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ? AND "
-                        + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " = ?";
-        String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid)};
-
-        ensureRecoveryServiceMetadataEntryExists(userId, uid);
-        return db.update(
-                RecoveryServiceMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
+        return setBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY,
+                publicKey.getEncoded());
     }
 
     /**
@@ -393,63 +384,27 @@
      */
     @Nullable
     public PublicKey getRecoveryServicePublicKey(int userId, int uid) {
-        SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
-
-        String[] projection = {
-                RecoveryServiceMetadataEntry._ID,
-                RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID,
-                RecoveryServiceMetadataEntry.COLUMN_NAME_UID,
-                RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY};
-        String selection =
-                RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ? AND "
-                        + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " = ?";
-        String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid)};
-
-        try (
-                Cursor cursor = db.query(
-                        RecoveryServiceMetadataEntry.TABLE_NAME,
-                        projection,
-                        selection,
-                        selectionArguments,
-                        /*groupBy=*/ null,
-                        /*having=*/ null,
-                        /*orderBy=*/ null)
-        ) {
-            int count = cursor.getCount();
-            if (count == 0) {
-                return null;
-            }
-            if (count > 1) {
-                Log.wtf(TAG,
-                        String.format(Locale.US,
-                                "%d PublicKey entries found for userId=%d uid=%d. "
-                                        + "Should only ever be 0 or 1.", count, userId, uid));
-                return null;
-            }
-            cursor.moveToFirst();
-            int idx = cursor.getColumnIndexOrThrow(
-                    RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY);
-            if (cursor.isNull(idx)) {
-                return null;
-            }
-            byte[] keyBytes = cursor.getBlob(idx);
-            try {
-                return decodeX509Key(keyBytes);
-            } catch (InvalidKeySpecException e) {
-                Log.wtf(TAG,
-                        String.format(Locale.US,
-                                "Recovery service public key entry cannot be decoded for "
-                                        + "userId=%d uid=%d.",
-                                userId, uid));
-                return null;
-            }
+        byte[] keyBytes =
+                getBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY);
+        if (keyBytes == null) {
+            return null;
+        }
+        try {
+            return decodeX509Key(keyBytes);
+        } catch (InvalidKeySpecException e) {
+            Log.wtf(TAG,
+                    String.format(Locale.US,
+                            "Recovery service public key entry cannot be decoded for "
+                                    + "userId=%d uid=%d.",
+                            userId, uid));
+            return null;
         }
     }
 
     /**
      * Updates the list of user secret types used for end-to-end encryption.
      * If no secret types are set, recovery snapshot will not be created.
-     * See {@code KeyStoreRecoveryMetadata}
+     * See {@code RecoveryMetadata}
      *
      * @param userId The userId of the profile the application is running under.
      * @param uid The uid of the application.
@@ -617,14 +572,14 @@
      *
      * @param userId The userId of the profile the application is running under.
      * @param uid The uid of the application.
-     * @param serverParameters The server parameters.
+     * @param serverParams The server parameters.
      * @return The primary key of the inserted row, or -1 if failed.
      *
      * @hide
      */
-    public long setServerParameters(int userId, int uid, long serverParameters) {
-        return setLong(userId, uid,
-                RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMETERS, serverParameters);
+    public long setServerParams(int userId, int uid, byte[] serverParams) {
+        return setBytes(userId, uid,
+                RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS, serverParams);
     }
 
     /**
@@ -638,9 +593,8 @@
      * @hide
      */
     @Nullable
-    public Long getServerParameters(int userId, int uid) {
-        return getLong(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMETERS);
-
+    public byte[] getServerParams(int userId, int uid) {
+        return getBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS);
     }
 
     /**
@@ -704,6 +658,7 @@
         return res != null && res != 0L;
     }
 
+
     /**
      * Returns given long value from the database.
      *
@@ -785,6 +740,86 @@
     }
 
     /**
+     * Returns given binary value from the database.
+     *
+     * @param userId The userId of the profile the application is running under.
+     * @param uid The uid of the application who initialized the local recovery components.
+     * @param key from {@code RecoveryServiceMetadataEntry}
+     * @return The value that were previously set, or null if there's none.
+     *
+     * @hide
+     */
+    private byte[] getBytes(int userId, int uid, String key) {
+        SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
+
+        String[] projection = {
+                RecoveryServiceMetadataEntry._ID,
+                RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID,
+                RecoveryServiceMetadataEntry.COLUMN_NAME_UID,
+                key};
+        String selection =
+                RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ? AND "
+                        + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " = ?";
+        String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid)};
+
+        try (
+            Cursor cursor = db.query(
+                    RecoveryServiceMetadataEntry.TABLE_NAME,
+                    projection,
+                    selection,
+                    selectionArguments,
+                    /*groupBy=*/ null,
+                    /*having=*/ null,
+                    /*orderBy=*/ null)
+        ) {
+            int count = cursor.getCount();
+            if (count == 0) {
+                return null;
+            }
+            if (count > 1) {
+                Log.wtf(TAG,
+                        String.format(Locale.US,
+                                "%d entries found for userId=%d uid=%d. "
+                                        + "Should only ever be 0 or 1.", count, userId, uid));
+                return null;
+            }
+            cursor.moveToFirst();
+            int idx = cursor.getColumnIndexOrThrow(key);
+            if (cursor.isNull(idx)) {
+                return null;
+            } else {
+                return cursor.getBlob(idx);
+            }
+        }
+    }
+
+    /**
+     * Sets a binary value in the database.
+     *
+     * @param userId The userId of the profile the application is running under.
+     * @param uid The uid of the application who initialized the local recovery components.
+     * @param key defined in {@code RecoveryServiceMetadataEntry}
+     * @param value new value.
+     * @return The primary key of the inserted row, or -1 if failed.
+     *
+     * @hide
+     */
+
+    private long setBytes(int userId, int uid, String key, byte[] value) {
+        SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
+        ContentValues values = new ContentValues();
+        values.put(key, value);
+        String selection =
+                RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ? AND "
+                        + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " = ?";
+        String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid)};
+
+        ensureRecoveryServiceMetadataEntryExists(userId, uid);
+        return db.update(
+                RecoveryServiceMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
+    }
+
+    /**
      * Creates an empty row in the recovery service metadata table if such a row doesn't exist for
      * the given userId and uid, so db.update will succeed.
      */
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 597ae4c..4ee282b 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -64,7 +64,7 @@
         static final String COLUMN_NAME_LAST_SYNCED_AT = "last_synced_at";
 
         /**
-         * Status of the key sync {@code RecoverableKeyStoreLoader#setRecoveryStatus}
+         * Status of the key sync {@code RecoveryManager#setRecoveryStatus}
          */
         static final String COLUMN_NAME_RECOVERY_STATUS = "recovery_status";
     }
@@ -130,6 +130,6 @@
         /**
          * The server parameters of the recovery service.
          */
-        static final String COLUMN_NAME_SERVER_PARAMETERS = "server_parameters";
+        static final String COLUMN_NAME_SERVER_PARAMS = "server_params";
     }
 }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
index 6eb47ee..d96671c 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
@@ -61,7 +61,7 @@
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES + " TEXT,"
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID + " INTEGER,"
-                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMETERS + " INTEGER,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS + " BLOB,"
                     + "UNIQUE("
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID  + ","
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + "))";
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
index 011b374..158b1e3 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
@@ -17,7 +17,7 @@
 package com.android.server.locksettings.recoverablekeystore.storage;
 
 import android.annotation.Nullable;
-import android.security.recoverablekeystore.KeyStoreRecoveryData;
+import android.security.keystore.RecoveryData;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -34,12 +34,12 @@
  */
 public class RecoverySnapshotStorage {
     @GuardedBy("this")
-    private final SparseArray<KeyStoreRecoveryData> mSnapshotByUid = new SparseArray<>();
+    private final SparseArray<RecoveryData> mSnapshotByUid = new SparseArray<>();
 
     /**
      * Sets the latest {@code snapshot} for the recovery agent {@code uid}.
      */
-    public synchronized void put(int uid, KeyStoreRecoveryData snapshot) {
+    public synchronized void put(int uid, RecoveryData snapshot) {
         mSnapshotByUid.put(uid, snapshot);
     }
 
@@ -47,7 +47,7 @@
      * Returns the latest snapshot for the recovery agent {@code uid}, or null if none exists.
      */
     @Nullable
-    public synchronized KeyStoreRecoveryData get(int uid) {
+    public synchronized RecoveryData get(int uid) {
         return mSnapshotByUid.get(uid);
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 3c47e85..ff9b2fd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2793,6 +2793,11 @@
                     handleNetworkPoliciesUpdateAL(true);
                 }
             }
+
+            final Intent intent = new Intent(SubscriptionManager.ACTION_SUBSCRIPTION_PLANS_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+            mContext.sendBroadcast(intent, android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -2949,7 +2954,7 @@
                     if (state <= ActivityManager.PROCESS_STATE_TOP) {
                         fout.print(" (fg)");
                     } else {
-                        fout.print(state <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+                        fout.print(state <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
                                 ? " (fg svc)" : " (bg)");
                     }
 
diff --git a/services/core/java/com/android/server/net/watchlist/OWNERS b/services/core/java/com/android/server/net/watchlist/OWNERS
new file mode 100644
index 0000000..a3d4b85
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/OWNERS
@@ -0,0 +1,3 @@
+rickywai@google.com
+alanstokes@google.com
+simonjw@google.com
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 575c44d..16b9257 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2917,12 +2917,34 @@
             }
         }
 
+        /**
+         * Sets the notification policy.  Apps that target API levels below
+         * {@link android.os.Build.VERSION_CODES#P} cannot make DND silence
+         * {@link Policy#PRIORITY_CATEGORY_ALARMS} or
+         * {@link Policy#PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER}
+         */
         @Override
         public void setNotificationPolicy(String pkg, Policy policy) {
             enforcePolicyAccess(pkg, "setNotificationPolicy");
             final long identity = Binder.clearCallingIdentity();
             try {
+                final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
+                        0, UserHandle.getUserId(MY_UID));
+
+                if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
+                    Policy currPolicy = mZenModeHelper.getNotificationPolicy();
+
+                    int priorityCategories = policy.priorityCategories
+                            | (currPolicy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS)
+                            | (currPolicy.priorityCategories &
+                            Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER);
+                    policy = new Policy(priorityCategories,
+                            policy.priorityCallSenders, policy.priorityMessageSenders,
+                            policy.suppressedVisualEffects);
+                }
+
                 mZenModeHelper.setNotificationPolicy(policy);
+            } catch (RemoteException e) {
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index a30e0639..fd9ffb2 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -278,7 +278,7 @@
 
     // VisibleForTesting
     public static String[] getExtraPeople(Bundle extras) {
-        Object people = extras.get(Notification.EXTRA_PEOPLE);
+        Object people = extras.get(Notification.EXTRA_PEOPLE_LIST);
         if (people instanceof String[]) {
             return (String[]) people;
         }
@@ -305,6 +305,16 @@
                 return array;
             }
 
+            if (arrayList.get(0) instanceof Notification.Person) {
+                ArrayList<Notification.Person> list = (ArrayList<Notification.Person>) arrayList;
+                final int N = list.size();
+                String[] array = new String[N];
+                for (int i = 0; i < N; i++) {
+                    array[i] = list.get(i).resolveToLegacyUri();
+                }
+                return array;
+            }
+
             return null;
         }
 
@@ -459,7 +469,9 @@
                     lookupResult = searchContacts(mContext, uri);
                 } else {
                     lookupResult = new LookupResult();  // invalid person for the cache
-                    Slog.w(TAG, "unsupported URI " + handle);
+                    if (!"name".equals(uri.getScheme())) {
+                        Slog.w(TAG, "unsupported URI " + handle);
+                    }
                 }
                 if (lookupResult != null) {
                     synchronized (mPeopleCache) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 700ccad..b5d2844 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -822,21 +822,24 @@
 
     @VisibleForTesting
     protected void applyRestrictions() {
-        final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
+        final boolean zenPriorityOnly = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        final boolean zenSilence  = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+        final boolean zenAlarmsOnly = mZenMode == Global.ZEN_MODE_ALARMS;
 
         // notification restrictions
         final boolean muteNotifications =
                 (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
         // call restrictions
-        final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
+        final boolean muteCalls = zenAlarmsOnly
+                || (zenPriorityOnly && !mConfig.allowCalls && !mConfig.allowRepeatCallers)
                 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
         // alarm restrictions
-        final boolean muteAlarms = zen && !mConfig.allowAlarms;
+        final boolean muteAlarms = zenPriorityOnly && !mConfig.allowAlarms;
         // alarm restrictions
-        final boolean muteMediaAndSystemSounds = zen && !mConfig.allowMediaSystemOther;
+        final boolean muteMediaAndSystemSounds = zenPriorityOnly && !mConfig.allowMediaSystemOther;
         // total silence restrictions
-        final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
-                || areAllBehaviorSoundsMuted();
+        final boolean muteEverything = zenSilence
+                || (zenPriorityOnly && areAllBehaviorSoundsMuted());
 
         for (int usage : AudioAttributes.SDK_USAGES) {
             final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index c964f91..af20cd7 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -49,7 +49,6 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
-import com.android.server.pm.permission.BasePermission;
 
 import libcore.io.IoUtils;
 import org.xmlpull.v1.XmlPullParser;
@@ -302,7 +301,7 @@
             // into account but also allow the value from the old computation to avoid
             // data loss.
             final String[] signaturesSha256Digests = PackageUtils.computeSignaturesSha256Digests(
-                    pkg.mSignatures);
+                    pkg.mSigningDetails.signatures);
             final String signaturesSha256Digest = PackageUtils.computeSignaturesSha256Digest(
                     signaturesSha256Digests);
 
@@ -313,7 +312,7 @@
             }
 
             // For backwards compatibility we accept match based on first signature
-            if (pkg.mSignatures.length > 1 && currentCookieFile.equals(computeInstantCookieFile(
+            if (pkg.mSigningDetails.signatures.length > 1 && currentCookieFile.equals(computeInstantCookieFile(
                     pkg.packageName, signaturesSha256Digests[0], userId))) {
                 return;
             }
@@ -1176,12 +1175,13 @@
             // We prefer the modern computation procedure where all certs are taken
             // into account and delete the file derived via the legacy hash computation.
             File newCookieFile = computeInstantCookieFile(pkg.packageName,
-                    PackageUtils.computeSignaturesSha256Digest(pkg.mSignatures), userId);
-            if (pkg.mSignatures.length > 0) {
-                File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId);
-                if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) {
-                    oldCookieFile.delete();
-                }
+                    PackageUtils.computeSignaturesSha256Digest(pkg.mSigningDetails.signatures), userId);
+            if (!pkg.mSigningDetails.hasSignatures()) {
+                Slog.wtf(LOG_TAG, "Parsed Instant App contains no valid signatures!");
+            }
+            File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+            if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) {
+                oldCookieFile.delete();
             }
             cancelPendingPersistLPw(pkg, userId);
             addPendingPersistCookieLPw(userId, pkg, cookie, newCookieFile);
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index fca9585..93d3b77 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -188,7 +188,7 @@
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Passed invalid package to keyset validation.");
         }
-        ArraySet<PublicKey> signingKeys = pkg.mSigningKeys;
+        ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys;
         if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Package has invalid signing-key-set.");
@@ -223,7 +223,7 @@
         PackageSetting ps = mPackages.get(pkg.packageName);
         Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName
                     + "does not have a corresponding entry in mPackages.");
-        addSigningKeySetToPackageLPw(ps, pkg.mSigningKeys);
+        addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys);
         if (pkg.mKeySetMapping != null) {
             addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping);
             if (pkg.mUpgradeKeySets != null) {
@@ -371,7 +371,7 @@
         long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
         for (int i = 0; i < upgradeKeySets.length; i++) {
             Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
-            if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
+            if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index b06b583..1717b3d 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -652,6 +652,7 @@
                             activityInfo.name.equals(component.getClassName())) {
                         // Found an activity with category launcher that matches
                         // this component so ok to launch.
+                        launchIntent.setPackage(null);
                         launchIntent.setComponent(component);
                         mContext.startActivityAsUser(launchIntent, opts, user);
                         return;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5577de8..a43818a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -58,7 +58,6 @@
 import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.Signature;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Binder;
@@ -84,6 +83,7 @@
 import android.util.ExceptionUtils;
 import android.util.MathUtils;
 import android.util.Slog;
+import android.util.apk.ApkSignatureVerifier;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.NativeLibraryHelper;
@@ -107,7 +107,7 @@
 import java.io.FileFilter;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -227,9 +227,7 @@
     @GuardedBy("mLock")
     private long mVersionCode;
     @GuardedBy("mLock")
-    private Signature[] mSignatures;
-    @GuardedBy("mLock")
-    private Certificate[][] mCertificates;
+    private PackageParser.SigningDetails mSigningDetails;
 
     /**
      * Path to the validated base APK for this session, which may point at an
@@ -857,7 +855,7 @@
         }
 
         Preconditions.checkNotNull(mPackageName);
-        Preconditions.checkNotNull(mSignatures);
+        Preconditions.checkNotNull(mSigningDetails);
         Preconditions.checkNotNull(mResolvedBaseFile);
 
         if (needToAskForPermissionsLocked()) {
@@ -938,7 +936,7 @@
 
         mRelinquished = true;
         mPm.installStage(mPackageName, stageDir, localObserver, params,
-                mInstallerPackageName, mInstallerUid, user, mCertificates);
+                mInstallerPackageName, mInstallerUid, user, mSigningDetails);
     }
 
     /**
@@ -957,7 +955,7 @@
             throws PackageManagerException {
         mPackageName = null;
         mVersionCode = -1;
-        mSignatures = null;
+        mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
 
         mResolvedBaseFile = null;
         mResolvedStagedFiles.clear();
@@ -990,11 +988,8 @@
         for (File addedFile : addedFiles) {
             final ApkLite apk;
             try {
-                int flags = PackageParser.PARSE_COLLECT_CERTIFICATES;
-                if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
-                    flags |= PackageParser.PARSE_IS_EPHEMERAL;
-                }
-                apk = PackageParser.parseApkLite(addedFile, flags);
+                apk = PackageParser.parseApkLite(
+                        addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
             }
@@ -1009,9 +1004,8 @@
                 mPackageName = apk.packageName;
                 mVersionCode = apk.getLongVersionCode();
             }
-            if (mSignatures == null) {
-                mSignatures = apk.signatures;
-                mCertificates = apk.certificates;
+            if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
+                mSigningDetails = apk.signingDetails;
             }
 
             assertApkConsistentLocked(String.valueOf(addedFile), apk);
@@ -1060,8 +1054,15 @@
                 mPackageName = pkgInfo.packageName;
                 mVersionCode = pkgInfo.getLongVersionCode();
             }
-            if (mSignatures == null) {
-                mSignatures = pkgInfo.signatures;
+            if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
+                try {
+                    mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
+                            pkgInfo.applicationInfo.sourceDir,
+                            PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
+                } catch (PackageParserException e) {
+                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                            "Couldn't obtain signatures from base APK");
+                }
             }
         }
 
@@ -1155,7 +1156,7 @@
                     + " version code " + apk.versionCode + " inconsistent with "
                     + mVersionCode);
         }
-        if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
+        if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     tag + " signatures are inconsistent");
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 44aad44..6e94523 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import static android.Manifest.permission.DELETE_PACKAGES;
+import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
 import static android.Manifest.permission.INSTALL_PACKAGES;
 import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
@@ -167,7 +168,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
-import android.content.pm.PackageManager.PackageInfoFlags;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ActivityIntentInfo;
@@ -176,6 +176,7 @@
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageParser.ParseFlags;
 import android.content.pm.PackageParser.ServiceIntentInfo;
+import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageUserState;
 import android.content.pm.ParceledListSlice;
@@ -337,7 +338,6 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
 import java.security.SecureRandom;
-import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -2697,6 +2697,12 @@
                                 mSettings.getDisabledSystemPkgLPr(ps.name);
                         if (disabledPs.codePath == null || !disabledPs.codePath.exists()
                                 || disabledPs.pkg == null) {
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Possibly deleted app: " + ps.dumpState_temp()
+        + "; path: " + (disabledPs.codePath == null ? "<<NULL>>":disabledPs.codePath)
+        + "; pkg: " + (disabledPs.pkg==null?"<<NULL>>":disabledPs.pkg.toString()));
+}
                             possiblyDeletedUpdatedSystemApps.add(ps.name);
                         }
                     }
@@ -2748,7 +2754,10 @@
                 for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                     PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                     mSettings.removeDisabledSystemPackageLPw(deletedAppName);
-
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "remove update; name: " + deletedAppName + ", exists? " + (deletedPkg != null));
+}
                     final String msg;
                     if (deletedPkg == null) {
                         // should have found an update, but, we didn't; remove everything
@@ -5360,7 +5369,7 @@
                     || filterAppAccessLPr(ps2, callingUid, callingUserId)) {
                 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
             }
-            return compareSignatures(p1.mSignatures, p2.mSignatures);
+            return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures);
         }
     }
 
@@ -8184,36 +8193,36 @@
     }
 
     private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
-            final @ParseFlags int parseFlags) throws PackageManagerException {
+            final @ParseFlags int parseFlags, boolean forceCollect) throws PackageManagerException {
         // When upgrading from pre-N MR1, verify the package time stamp using the package
         // directory and not the APK file.
         final long lastModifiedTime = mIsPreNMR1Upgrade
                 ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
-        if (ps != null
+        if (ps != null && !forceCollect
                 && ps.codePathString.equals(pkg.codePath)
                 && ps.timeStamp == lastModifiedTime
                 && !isCompatSignatureUpdateNeeded(pkg)
                 && !isRecoverSignatureUpdateNeeded(pkg)) {
-            long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
-            final KeySetManagerService ksms = mSettings.mKeySetManagerService;
-            ArraySet<PublicKey> signingKs;
-            synchronized (mPackages) {
-                signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId);
-            }
             if (ps.signatures.mSignatures != null
                     && ps.signatures.mSignatures.length != 0
-                    && signingKs != null) {
-                // Optimization: reuse the existing cached certificates
+                    && ps.signatures.mSignatureSchemeVersion != SignatureSchemeVersion.UNKNOWN) {
+                // Optimization: reuse the existing cached signing data
                 // if the package appears to be unchanged.
-                pkg.mSignatures = ps.signatures.mSignatures;
-                pkg.mSigningKeys = signingKs;
-                return;
+                try {
+                    pkg.mSigningDetails = new PackageParser.SigningDetails(ps.signatures.mSignatures,
+                            ps.signatures.mSignatureSchemeVersion);
+                    return;
+                } catch (CertificateException e) {
+                    Slog.e(TAG, "Attempt to read public keys from persisted signatures failed for "
+                                    + ps.name, e);
+                }
             }
 
             Slog.w(TAG, "PackageSetting for " + ps.name
                     + " is missing signatures.  Collecting certs again to recover them.");
         } else {
-            Slog.i(TAG, toString() + " changed; collecting certs");
+            Slog.i(TAG, pkg.codePath + " changed; collecting certs" +
+                    (forceCollect ? " (forced)" : ""));
         }
 
         try {
@@ -8293,14 +8302,14 @@
         }
 
         // Scan the parent
-        PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, parseFlags,
+        PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
                 scanFlags, currentTime, user);
 
         // Scan the children
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
             PackageParser.Package childPackage = pkg.childPackages.get(i);
-            scanPackageInternalLI(childPackage, parseFlags, scanFlags,
+            addForInitLI(childPackage, parseFlags, scanFlags,
                     currentTime, user);
         }
 
@@ -8312,313 +8321,308 @@
         return scannedPkg;
     }
 
+    // Temporary to catch potential issues with refactoring
+    private static boolean REFACTOR_DEBUG = true;
     /**
-     *  Scans a package and returns the newly parsed package.
-     *  @throws PackageManagerException on a parse error.
+     * Adds a new package to the internal data structures during platform initialization.
+     * <p>After adding, the package is known to the system and available for querying.
+     * <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
+     * etc...], additional checks are performed. Basic verification [such as ensuring
+     * matching signatures, checking version codes, etc...] occurs if the package is
+     * identical to a previously known package. If the package fails a signature check,
+     * the version installed on /data will be removed. If the version of the new package
+     * is less than or equal than the version on /data, it will be ignored.
+     * <p>Regardless of the package location, the results are applied to the internal
+     * structures and the package is made available to the rest of the system.
+     * <p>NOTE: The return value should be removed. It's the passed in package object.
      */
-    private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg,
+    private PackageParser.Package addForInitLI(PackageParser.Package pkg,
             @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user)
                     throws PackageManagerException {
-        PackageSetting ps = null;
-        PackageSetting updatedPs;
-        // reader
-        synchronized (mPackages) {
-            // Look to see if we already know about this package.
-            String oldName = mSettings.getRenamedPackageLPr(pkg.packageName);
-            if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
-                // This package has been renamed to its original name.  Let's
-                // use that.
-                ps = mSettings.getPackageLPr(oldName);
-            }
-            // If there was no original package, see one for the real package name.
-            if (ps == null) {
-                ps = mSettings.getPackageLPr(pkg.packageName);
-            }
-            // Check to see if this package could be hiding/updating a system
-            // package.  Must look for it either under the original or real
-            // package name depending on our state.
-            updatedPs = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
-            if (DEBUG_INSTALL && updatedPs != null) Slog.d(TAG, "updatedPkg = " + updatedPs);
+        final boolean scanSystemPartition = (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
+        final String renamedPkgName;
+        final PackageSetting disabledPkgSetting;
+        final boolean isSystemPkgUpdated;
+        final boolean pkgAlreadyExists;
+        PackageSetting pkgSetting;
 
-            // If this is a package we don't know about on the system partition, we
-            // may need to remove disabled child packages on the system partition
-            // or may need to not add child packages if the parent apk is updated
-            // on the data partition and no longer defines this child package.
-            if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
-                // If this is a parent package for an updated system app and this system
-                // app got an OTA update which no longer defines some of the child packages
-                // we have to prune them from the disabled system packages.
-                PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
-                if (disabledPs != null) {
-                    final int scannedChildCount = (pkg.childPackages != null)
-                            ? pkg.childPackages.size() : 0;
-                    final int disabledChildCount = disabledPs.childPackageNames != null
-                            ? disabledPs.childPackageNames.size() : 0;
-                    for (int i = 0; i < disabledChildCount; i++) {
-                        String disabledChildPackageName = disabledPs.childPackageNames.get(i);
-                        boolean disabledPackageAvailable = false;
-                        for (int j = 0; j < scannedChildCount; j++) {
-                            PackageParser.Package childPkg = pkg.childPackages.get(j);
-                            if (childPkg.packageName.equals(disabledChildPackageName)) {
-                                disabledPackageAvailable = true;
-                                break;
-                            }
-                         }
-                         if (!disabledPackageAvailable) {
-                             mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
-                         }
-                    }
-                }
-            }
-        }
-
-        final boolean isUpdatedPkg = updatedPs != null;
-        final boolean isUpdatedSystemPkg = isUpdatedPkg && (scanFlags & SCAN_AS_SYSTEM) != 0;
-        boolean isUpdatedPkgBetter = false;
-        // First check if this is a system package that may involve an update
-        if (isUpdatedSystemPkg) {
-            // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
-            // it needs to drop FLAG_PRIVILEGED.
-            if (locationIsPrivileged(pkg.codePath)) {
-                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-            } else {
-                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-            }
-            // If new package is not located in "/oem" (e.g. due to an OTA),
-            // it needs to drop FLAG_OEM.
-            if (locationIsOem(pkg.codePath)) {
-                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
-            } else {
-                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_OEM;
-            }
-            // If new package is not located in "/vendor" (e.g. due to an OTA),
-            // it needs to drop FLAG_VENDOR.
-            if (locationIsVendor(pkg.codePath)) {
-                updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
-            } else {
-                updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VENDOR;
-            }
-
-            if (ps != null && !ps.codePathString.equals(pkg.codePath)) {
-                // The path has changed from what was last scanned...  check the
-                // version of the new path against what we have stored to determine
-                // what to do.
-                if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
-                if (pkg.getLongVersionCode() <= ps.versionCode) {
-                    // The system package has been updated and the code path does not match
-                    // Ignore entry. Skip it.
-                    if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + pkg.codePath
-                            + " ignored: updated version " + ps.versionCode
-                            + " better than this " + pkg.getLongVersionCode());
-                    if (!updatedPs.codePathString.equals(pkg.codePath)) {
-                        Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
-                                + ps.name + " changing from " + updatedPs.codePathString
-                                + " to " + pkg.codePath);
-                        final File codePath = new File(pkg.codePath);
-                        updatedPs.codePath = codePath;
-                        updatedPs.codePathString = pkg.codePath;
-                        updatedPs.resourcePath = codePath;
-                        updatedPs.resourcePathString = pkg.codePath;
-                    }
-                    updatedPs.pkg = pkg;
-                    updatedPs.versionCode = pkg.getLongVersionCode();
-
-                    // Update the disabled system child packages to point to the package too.
-                    final int childCount = updatedPs.childPackageNames != null
-                            ? updatedPs.childPackageNames.size() : 0;
-                    for (int i = 0; i < childCount; i++) {
-                        String childPackageName = updatedPs.childPackageNames.get(i);
-                        PackageSetting updatedChildPkg = mSettings.getDisabledSystemPkgLPr(
-                                childPackageName);
-                        if (updatedChildPkg != null) {
-                            updatedChildPkg.pkg = pkg;
-                            updatedChildPkg.versionCode = pkg.getLongVersionCode();
-                        }
-                    }
-                } else {
-                    // The current app on the system partition is better than
-                    // what we have updated to on the data partition; switch
-                    // back to the system partition version.
-                    // At this point, its safely assumed that package installation for
-                    // apps in system partition will go through. If not there won't be a working
-                    // version of the app
-                    // writer
-                    synchronized (mPackages) {
-                        // Just remove the loaded entries from package lists.
-                        mPackages.remove(ps.name);
-                    }
-
-                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
-                            + " reverting from " + ps.codePathString
-                            + ": new version " + pkg.getLongVersionCode()
-                            + " better than installed " + ps.versionCode);
-
-                    InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
-                            ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
-                    synchronized (mInstallLock) {
-                        args.cleanUpResourcesLI();
-                    }
-                    synchronized (mPackages) {
-                        mSettings.enableSystemPackageLPw(ps.name);
-                    }
-                    isUpdatedPkgBetter = true;
-                }
-            }
-        }
-
-        String resourcePath = null;
-        String baseResourcePath = null;
-        if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !isUpdatedPkgBetter) {
-            if (ps != null && ps.resourcePathString != null) {
-                resourcePath = ps.resourcePathString;
-                baseResourcePath = ps.resourcePathString;
-            } else {
-                // Should not happen at all. Just log an error.
-                Slog.e(TAG, "Resource path not set for package " + pkg.packageName);
-            }
-        } else {
-            resourcePath = pkg.codePath;
-            baseResourcePath = pkg.baseCodePath;
-        }
-
-        // Set application objects path explicitly.
+        // NOTE: installPackageLI() has the same code to setup the package's
+        // application info. This probably should be done lower in the call
+        // stack [such as scanPackageOnly()]. However, we verify the application
+        // info prior to that [in scanPackageNew()] and thus have to setup
+        // the application info early.
         pkg.setApplicationVolumeUuid(pkg.volumeUuid);
         pkg.setApplicationInfoCodePath(pkg.codePath);
         pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
         pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
-        pkg.setApplicationInfoResourcePath(resourcePath);
-        pkg.setApplicationInfoBaseResourcePath(baseResourcePath);
+        pkg.setApplicationInfoResourcePath(pkg.codePath);
+        pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
         pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
 
-        // throw an exception if we have an update to a system application, but, it's not more
-        // recent than the package we've already scanned
-        if (isUpdatedSystemPkg && !isUpdatedPkgBetter) {
-            // Set CPU Abis to application info.
-            if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
-                final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPs);
-                derivePackageAbi(pkg, cpuAbiOverride, false);
-            } else {
-                pkg.applicationInfo.primaryCpuAbi = updatedPs.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = updatedPs.secondaryCpuAbiString;
+        synchronized (mPackages) {
+            renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
+            final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Add pkg: " + pkg.packageName + (realPkgName==null?"":", realName: " + realPkgName));
+}
+            if (realPkgName != null) {
+                ensurePackageRenamed(pkg, renamedPkgName);
             }
-            pkg.mExtras = updatedPs;
+            final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
+            final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName);
+            pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
+            pkgAlreadyExists = pkgSetting != null;
+            final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
+            disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
+            isSystemPkgUpdated = disabledPkgSetting != null;
 
+            if (DEBUG_INSTALL && isSystemPkgUpdated) {
+                Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
+            }
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "SSP? " + scanSystemPartition
+        + ", exists? " + pkgAlreadyExists + (pkgAlreadyExists?" "+pkgSetting.toString():"")
+        + ", upgraded? " + isSystemPkgUpdated + (isSystemPkgUpdated?" "+disabledPkgSetting.toString():""));
+}
+
+            final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
+                    ? mSettings.getSharedUserLPw(pkg.mSharedUserId,
+                            0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
+                    : null;
+            if (DEBUG_PACKAGE_SCANNING
+                    && (parseFlags & PackageParser.PARSE_CHATTY) != 0
+                    && sharedUserSetting != null) {
+                Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+                        + " (uid=" + sharedUserSetting.userId + "):"
+                        + " packages=" + sharedUserSetting.packages);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Shared UserID " + pkg.mSharedUserId
+        + " (uid=" + sharedUserSetting.userId + "):"
+        + " packages=" + sharedUserSetting.packages);
+}
+            }
+
+            if (scanSystemPartition) {
+                // Potentially prune child packages. If the application on the /system
+                // partition has been updated via OTA, but, is still disabled by a
+                // version on /data, cycle through all of its children packages and
+                // remove children that are no longer defined.
+                if (isSystemPkgUpdated) {
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Disable child packages");
+}
+                    final int scannedChildCount = (pkg.childPackages != null)
+                            ? pkg.childPackages.size() : 0;
+                    final int disabledChildCount = disabledPkgSetting.childPackageNames != null
+                            ? disabledPkgSetting.childPackageNames.size() : 0;
+                    for (int i = 0; i < disabledChildCount; i++) {
+                        String disabledChildPackageName =
+                                disabledPkgSetting.childPackageNames.get(i);
+                        boolean disabledPackageAvailable = false;
+                        for (int j = 0; j < scannedChildCount; j++) {
+                            PackageParser.Package childPkg = pkg.childPackages.get(j);
+                            if (childPkg.packageName.equals(disabledChildPackageName)) {
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Ignore " + disabledChildPackageName);
+}
+                                disabledPackageAvailable = true;
+                                break;
+                            }
+                        }
+                        if (!disabledPackageAvailable) {
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Disable " + disabledChildPackageName);
+}
+                            mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
+                        }
+                    }
+                    // we're updating the disabled package, so, scan it as the package setting
+                    final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
+                            disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */,
+                            null /* originalPkgSetting */, null, parseFlags, scanFlags,
+                            (pkg == mPlatformPackage), user);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Scan disabled system package");
+Slog.e("TODD",
+        "Pre: " + request.pkgSetting.dumpState_temp());
+}
+final ScanResult result =
+                    scanPackageOnlyLI(request, mFactoryTest, -1L);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Post: " + (result.success?result.pkgSetting.dumpState_temp():"FAILED scan"));
+}
+                }
+            }
+        }
+
+        final boolean newPkgChangedPaths =
+                pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "paths changed? " + newPkgChangedPaths
+        + "; old: " + pkg.codePath
+        + ", new: " + (pkgSetting==null?"<<NULL>>":pkgSetting.codePathString));
+}
+        final boolean newPkgVersionGreater =
+                pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode;
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "version greater? " + newPkgVersionGreater
+        + "; old: " + pkg.getLongVersionCode()
+        + ", new: " + (pkgSetting==null?"<<NULL>>":pkgSetting.versionCode));
+}
+        final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
+                && newPkgChangedPaths && newPkgVersionGreater;
+if (REFACTOR_DEBUG) {
+    Slog.e("TODD",
+            "system better? " + isSystemPkgBetter);
+}
+        if (isSystemPkgBetter) {
+            // The version of the application on /system is greater than the version on
+            // /data. Switch back to the application on /system.
+            // It's safe to assume the application on /system will correctly scan. If not,
+            // there won't be a working copy of the application.
+            synchronized (mPackages) {
+                // just remove the loaded entries from package lists
+                mPackages.remove(pkgSetting.name);
+            }
+
+            logCriticalInfo(Log.WARN,
+                    "System package updated;"
+                    + " name: " + pkgSetting.name
+                    + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
+                    + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "System package changed;"
+        + " name: " + pkgSetting.name
+        + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
+        + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+}
+
+            final InstallArgs args = createInstallArgsForExisting(
+                    packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString,
+                    pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+            args.cleanUpResourcesLI();
+            synchronized (mPackages) {
+                mSettings.enableSystemPackageLPw(pkgSetting.name);
+            }
+        }
+
+        if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "THROW exception; system pkg version not good enough");
+}
+            // The version of the application on the /system partition is less than or
+            // equal to the version on the /data partition. Throw an exception and use
+            // the application already installed on the /data partition.
             throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
-                    + pkg.codePath + " ignored: updated version " + updatedPs.versionCode
+                    + pkg.codePath + " ignored: updated version " + disabledPkgSetting.versionCode
                     + " better than this " + pkg.getLongVersionCode());
         }
 
-        if (isUpdatedPkg) {
-            // updated system applications don't initially have the SCAN_AS_SYSTEM flag set
-            scanFlags |= SCAN_AS_SYSTEM;
+        // Verify certificates against what was last scanned. If it is an updated priv app, we will
+        // force the verification. Full apk verification will happen unless apk verity is set up for
+        // the file. In that case, only small part of the apk is verified upfront.
+        collectCertificatesLI(pkgSetting, pkg, parseFlags,
+                PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting));
 
-            // An updated privileged application will not have the PARSE_IS_PRIVILEGED
-            // flag set initially
-            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
-                scanFlags |= SCAN_AS_PRIVILEGED;
-            }
-
-            // An updated OEM app will not have the SCAN_AS_OEM
-            // flag set initially
-            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
-                scanFlags |= SCAN_AS_OEM;
-            }
-
-            // An updated vendor app will not have the SCAN_AS_VENDOR
-            // flag set initially
-            if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
-                scanFlags |= SCAN_AS_VENDOR;
-            }
-        }
-
-        // Verify certificates against what was last scanned
-        collectCertificatesLI(ps, pkg, parseFlags);
-
-        /*
-         * A new system app appeared, but we already had a non-system one of the
-         * same name installed earlier.
-         */
         boolean shouldHideSystemApp = false;
-        if (!isUpdatedPkg && ps != null
-                && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
-            /*
-             * Check to make sure the signatures match first. If they don't,
-             * wipe the installed application and its data.
-             */
-            if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
+        // A new application appeared on /system, but, we already have a copy of
+        // the application installed on /data.
+        if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
+                && !pkgSetting.isSystem()) {
+            // if the signatures don't match, wipe the installed application and its data
+            if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSigningDetails.signatures)
                     != PackageManager.SIGNATURE_MATCH) {
-                logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
-                        + " signatures don't match existing userdata copy; removing");
+                logCriticalInfo(Log.WARN,
+                        "System package signature mismatch;"
+                        + " name: " + pkgSetting.name);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "System package signature mismatch;"
+        + " name: " + pkgSetting.name);
+}
                 try (PackageFreezer freezer = freezePackage(pkg.packageName,
                         "scanPackageInternalLI")) {
                     deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
                 }
-                ps = null;
-            } else {
-                /*
-                 * If the newly-added system app is an older version than the
-                 * already installed version, hide it. It will be scanned later
-                 * and re-added like an update.
-                 */
-                if (pkg.getLongVersionCode() <= ps.versionCode) {
-                    shouldHideSystemApp = true;
-                    logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + pkg.codePath
-                            + " but new version " + pkg.getLongVersionCode()
-                            + " better than installed " + ps.versionCode + "; hiding system");
-                } else {
-                    /*
-                     * The newly found system app is a newer version that the
-                     * one previously installed. Simply remove the
-                     * already-installed application and replace it with our own
-                     * while keeping the application data.
-                     */
-                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
-                            + " reverting from " + ps.codePathString + ": new version "
-                            + pkg.getLongVersionCode() + " better than installed "
-                            + ps.versionCode);
-                    InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
-                            ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
-                    synchronized (mInstallLock) {
-                        args.cleanUpResourcesLI();
-                    }
+                pkgSetting = null;
+            } else if (newPkgVersionGreater) {
+                // The application on /system is newer than the application on /data.
+                // Simply remove the application on /data [keeping application data]
+                // and replace it with the version on /system.
+                logCriticalInfo(Log.WARN,
+                        "System package enabled;"
+                        + " name: " + pkgSetting.name
+                        + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
+                        + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "System package enabled;"
+        + " name: " + pkgSetting.name
+        + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
+        + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+}
+                InstallArgs args = createInstallArgsForExisting(
+                        packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString,
+                        pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+                synchronized (mInstallLock) {
+                    args.cleanUpResourcesLI();
                 }
+            } else {
+                // The application on /system is older than the application on /data. Hide
+                // the application on /system and the version on /data will be scanned later
+                // and re-added like an update.
+                shouldHideSystemApp = true;
+                logCriticalInfo(Log.INFO,
+                        "System package disabled;"
+                        + " name: " + pkgSetting.name
+                        + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
+                        + "; new: " + pkg.codePath + " @ " + pkg.codePath);
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "System package disabled;"
+        + " name: " + pkgSetting.name
+        + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
+        + "; new: " + pkg.codePath + " @ " + pkg.codePath);
+}
             }
         }
 
-        // The apk is forward locked (not public) if its code and resources
-        // are kept in different files. (except for app in either system or
-        // vendor path).
-        // TODO grab this value from PackageSettings
-        if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
-            if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
-                parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
-            }
-        }
-
-        final int userId = ((user == null) ? 0 : user.getIdentifier());
-        if (ps != null && ps.getInstantApp(userId)) {
-            scanFlags |= SCAN_AS_INSTANT_APP;
-        }
-        if (ps != null && ps.getVirtulalPreload(userId)) {
-            scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
-        }
-
-        // Note that we invoke the following method only if we are about to unpack an application
-        PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Scan package");
+Slog.e("TODD",
+        "Pre: " + (pkgSetting==null?"<<NONE>>":pkgSetting.dumpState_temp()));
+}
+        final PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags
                 | SCAN_UPDATE_SIGNATURE, currentTime, user);
+if (REFACTOR_DEBUG) {
+pkgSetting = mSettings.getPackageLPr(pkg.packageName);
+Slog.e("TODD",
+        "Post: " + (pkgSetting==null?"<<NONE>>":pkgSetting.dumpState_temp()));
+}
 
-        /*
-         * If the system app should be overridden by a previously installed
-         * data, hide the system app now and let the /data/app scan pick it up
-         * again.
-         */
         if (shouldHideSystemApp) {
+if (REFACTOR_DEBUG) {
+Slog.e("TODD",
+        "Disable package: " + pkg.packageName);
+}
             synchronized (mPackages) {
                 mSettings.disableSystemPackageLPw(pkg.packageName, true);
             }
         }
-
         return scannedPkg;
     }
 
@@ -9518,9 +9522,10 @@
                     final String[] expectedCertDigests = requiredCertDigests[i];
                     // For apps targeting O MR1 we require explicit enumeration of all certs.
                     final String[] libCertDigests = (targetSdk > Build.VERSION_CODES.O)
-                            ? PackageUtils.computeSignaturesSha256Digests(libPkg.mSignatures)
+                            ? PackageUtils.computeSignaturesSha256Digests(
+                            libPkg.mSigningDetails.signatures)
                             : PackageUtils.computeSignaturesSha256Digests(
-                                    new Signature[]{libPkg.mSignatures[0]});
+                                    new Signature[]{libPkg.mSigningDetails.signatures[0]});
 
                     // Take a shortcut if sizes don't match. Note that if an app doesn't
                     // target O we don't parse the "additional-certificate" tags similarly
@@ -9717,9 +9722,52 @@
         }
     }
 
+    /**
+     * Returns the actual scan flags depending upon the state of the other settings.
+     * <p>Updated system applications will not have the following flags set
+     * by default and need to be adjusted after the fact:
+     * <ul>
+     * <li>{@link #SCAN_AS_SYSTEM}</li>
+     * <li>{@link #SCAN_AS_PRIVILEGED}</li>
+     * <li>{@link #SCAN_AS_OEM}</li>
+     * <li>{@link #SCAN_AS_VENDOR}</li>
+     * <li>{@link #SCAN_AS_INSTANT_APP}</li>
+     * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
+     * </ul>
+     */
+    private static @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
+            PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user) {
+        if (disabledPkgSetting != null) {
+            // updated system application, must at least have SCAN_AS_SYSTEM
+            scanFlags |= SCAN_AS_SYSTEM;
+            if ((disabledPkgSetting.pkgPrivateFlags
+                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+                scanFlags |= SCAN_AS_PRIVILEGED;
+            }
+            if ((disabledPkgSetting.pkgPrivateFlags
+                    & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
+                scanFlags |= SCAN_AS_OEM;
+            }
+            if ((disabledPkgSetting.pkgPrivateFlags
+                    & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
+                scanFlags |= SCAN_AS_VENDOR;
+            }
+        }
+        if (pkgSetting != null) {
+            final int userId = ((user == null) ? 0 : user.getIdentifier());
+            if (pkgSetting.getInstantApp(userId)) {
+                scanFlags |= SCAN_AS_INSTANT_APP;
+            }
+            if (pkgSetting.getVirtulalPreload(userId)) {
+                scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
+            }
+        }
+        return scanFlags;
+    }
+
     @GuardedBy("mInstallLock")
     private PackageParser.Package scanPackageNewLI(@NonNull PackageParser.Package pkg,
-            final @ParseFlags int parseFlags, final @ScanFlags int scanFlags, long currentTime,
+            final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
 
         final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
@@ -9737,6 +9785,7 @@
                     + " was transferred to another, but its .apk remains");
         }
 
+        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user);
         synchronized (mPackages) {
             applyPolicy(pkg, parseFlags, scanFlags);
             assertPackageIsValid(pkg, parseFlags, scanFlags);
@@ -9791,6 +9840,7 @@
         final @ScanFlags int scanFlags = request.scanFlags;
         final PackageSetting oldPkgSetting = request.oldPkgSetting;
         final PackageSetting originalPkgSetting = request.originalPkgSetting;
+        final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
         final UserHandle user = request.user;
         final String realPkgName = request.realPkgName;
         final PackageSetting pkgSetting = result.pkgSetting;
@@ -9856,14 +9906,14 @@
             if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
                 // We just determined the app is signed correctly, so bring
                 // over the latest parsed certs.
-                pkgSetting.signatures.mSignatures = pkg.mSignatures;
+                pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures;
             } else {
                 if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                     throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                             "Package " + pkg.packageName + " upgrade keys do not match the "
                                     + "previously installed version");
                 } else {
-                    pkgSetting.signatures.mSignatures = pkg.mSignatures;
+                    pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures;
                     String msg = "System package " + pkg.packageName
                             + " signature changed; retaining data.";
                     reportSettingsProblem(Log.WARN, msg);
@@ -9873,8 +9923,8 @@
             try {
                 final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
                 final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
-                final boolean compatMatch = verifySignatures(signatureCheckPs, pkg.mSignatures,
-                        compareCompat, compareRecover);
+                final boolean compatMatch = verifySignatures(signatureCheckPs, disabledPkgSetting,
+                        pkg.mSigningDetails, compareCompat, compareRecover);
                 // The new KeySets will be re-added later in the scanning process.
                 if (compatMatch) {
                     synchronized (mPackages) {
@@ -9883,14 +9933,14 @@
                 }
                 // We just determined the app is signed correctly, so bring
                 // over the latest parsed certs.
-                pkgSetting.signatures.mSignatures = pkg.mSignatures;
+                pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures;
             } catch (PackageManagerException e) {
                 if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                     throw e;
                 }
                 // The signature has changed, but this package is in the system
                 // image...  let's recover!
-                pkgSetting.signatures.mSignatures = pkg.mSignatures;
+                pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures;
                 // However...  if this package is part of a shared user, but it
                 // doesn't match the signature of the shared user, let's fail.
                 // What this means is that you can't change the signatures
@@ -9898,7 +9948,7 @@
                 // that unreasonable.
                 if (signatureCheckPs.sharedUser != null) {
                     if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures,
-                            pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
+                            pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) {
                         throw new PackageManagerException(
                                 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
                                 "Signature mismatch for shared user: "
@@ -9963,10 +10013,16 @@
      */
     private static @Nullable String getRealPackageName(@NonNull PackageParser.Package pkg,
             @Nullable String renamedPkgName) {
-        if (pkg.mOriginalPackages == null || !pkg.mOriginalPackages.contains(renamedPkgName)) {
-            return null;
+        if (isPackageRenamed(pkg, renamedPkgName)) {
+            return pkg.mRealPackage;
         }
-        return pkg.mRealPackage;
+        return null;
+    }
+
+    /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */
+    private static boolean isPackageRenamed(@NonNull PackageParser.Package pkg,
+            @Nullable String renamedPkgName) {
+        return pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(renamedPkgName);
     }
 
     /**
@@ -9979,7 +10035,7 @@
     @GuardedBy("mPackages")
     private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg,
             @Nullable String renamedPkgName) {
-        if (pkg.mOriginalPackages == null || pkg.mOriginalPackages.contains(renamedPkgName)) {
+        if (!isPackageRenamed(pkg, renamedPkgName)) {
             return null;
         }
         for (int i = pkg.mOriginalPackages.size() - 1; i >= 0; --i) {
@@ -10102,7 +10158,6 @@
             usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
             pkg.usesStaticLibraries.toArray(usesStaticLibraries);
         }
-
         final boolean createNewPackage = (pkgSetting == null);
         if (createNewPackage) {
             final String parentPackageName = (pkg.parentPackage != null)
@@ -10126,17 +10181,17 @@
             // secondaryCpuAbi are not known at this point so we always update them
             // to null here, only to reset them at a later point.
             Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
-                    destCodeFile, pkg.applicationInfo.nativeLibraryDir,
+                    destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir,
                     pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
                     pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
                     pkg.getChildPackageNames(), UserManagerService.getInstance(),
                     usesStaticLibraries, pkg.usesStaticLibrariesVersions);
         }
         if (createNewPackage && originalPkgSetting != null) {
-            // If we are first transitioning from an original package,
-            // fix up the new package's name now.  We need to do this after
-            // looking up the package under its new name, so getPackageLP
-            // can take care of fiddling things correctly.
+            // This is the initial transition from the original package, so,
+            // fix up the new package's name now. We must do this after looking
+            // up the package under its new name, so getPackageLP takes care of
+            // fiddling things correctly.
             pkg.setPackageName(originalPkgSetting.name);
 
             // File a report about this.
@@ -10223,7 +10278,7 @@
         // would've already compiled the app without taking the package setting into
         // account.
         if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
-            if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
+            if (cpuAbiOverride == null && pkg.packageName != null) {
                 Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
                         " for package " + pkg.packageName);
             }
@@ -10238,7 +10293,7 @@
         pkg.cpuAbiOverride = cpuAbiOverride;
 
         if (DEBUG_ABI_SELECTION) {
-            Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.applicationInfo.packageName
+            Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.packageName
                     + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
                     + pkg.applicationInfo.nativeLibraryRootRequiresIsa);
         }
@@ -10293,6 +10348,22 @@
         }
         pkgSetting.setTimeStamp(scanFileTime);
 
+        pkgSetting.pkg = pkg;
+        pkgSetting.pkgFlags = pkg.applicationInfo.flags;
+        if (pkg.getLongVersionCode() != pkgSetting.versionCode) {
+            pkgSetting.versionCode = pkg.getLongVersionCode();
+        }
+        // Update volume if needed
+        final String volumeUuid = pkg.applicationInfo.volumeUuid;
+        if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
+            Slog.i(PackageManagerService.TAG,
+                    "Update" + (pkgSetting.isSystem() ? " system" : "")
+                    + " package " + pkg.packageName
+                    + " volume from " + pkgSetting.volumeUuid
+                    + " to " + volumeUuid);
+            pkgSetting.volumeUuid = volumeUuid;
+        }
+
         return new ScanResult(true, pkgSetting, changedAbiCodePath);
     }
 
@@ -13204,7 +13275,7 @@
     void installStage(String packageName, File stagedDir,
             IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
             String installerPackageName, int installerUid, UserHandle user,
-            Certificate[][] certificates) {
+            PackageParser.SigningDetails signingDetails) {
         if (DEBUG_EPHEMERAL) {
             if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
                 Slog.d(TAG, "Ephemeral install of " + packageName);
@@ -13222,7 +13293,7 @@
         final InstallParams params = new InstallParams(origin, null, observer,
                 sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
                 verificationInfo, user, sessionParams.abiOverride,
-                sessionParams.grantedRuntimePermissions, certificates, installReason);
+                sessionParams.grantedRuntimePermissions, signingDetails, installReason);
         params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -13826,7 +13897,7 @@
             final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName);
             if (pkg == null) {
                 return -1;
-            } else if (pkg.mSignatures.length != 1) {
+            } else if (pkg.mSigningDetails.signatures.length != 1) {
                 Slog.i(TAG, "Verifier package " + verifierInfo.packageName
                         + " has more than one signature; ignoring");
                 return -1;
@@ -13840,7 +13911,7 @@
 
             final byte[] expectedPublicKey;
             try {
-                final Signature verifierSig = pkg.mSignatures[0];
+                final Signature verifierSig = pkg.mSigningDetails.signatures[0];
                 final PublicKey publicKey = verifierSig.getPublicKey();
                 expectedPublicKey = publicKey.getEncoded();
             } catch (CertificateException e) {
@@ -14532,13 +14603,13 @@
         final String packageAbiOverride;
         final String[] grantedRuntimePermissions;
         final VerificationInfo verificationInfo;
-        final Certificate[][] certificates;
+        final PackageParser.SigningDetails signingDetails;
         final int installReason;
 
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
                 VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
-                String[] grantedPermissions, Certificate[][] certificates, int installReason) {
+                String[] grantedPermissions, PackageParser.SigningDetails signingDetails, int installReason) {
             super(user);
             this.origin = origin;
             this.move = move;
@@ -14549,7 +14620,7 @@
             this.verificationInfo = verificationInfo;
             this.packageAbiOverride = packageAbiOverride;
             this.grantedRuntimePermissions = grantedPermissions;
-            this.certificates = certificates;
+            this.signingDetails = signingDetails;
             this.installReason = installReason;
         }
 
@@ -14980,7 +15051,7 @@
         /** If non-null, drop an async trace when the install completes */
         final String traceMethod;
         final int traceCookie;
-        final Certificate[][] certificates;
+        final PackageParser.SigningDetails signingDetails;
         final int installReason;
 
         // The list of instruction sets supported by this app. This is currently
@@ -14992,7 +15063,7 @@
                 int installFlags, String installerPackageName, String volumeUuid,
                 UserHandle user, String[] instructionSets,
                 String abiOverride, String[] installGrantPermissions,
-                String traceMethod, int traceCookie, Certificate[][] certificates,
+                String traceMethod, int traceCookie, PackageParser.SigningDetails signingDetails,
                 int installReason) {
             this.origin = origin;
             this.move = move;
@@ -15006,7 +15077,7 @@
             this.installGrantPermissions = installGrantPermissions;
             this.traceMethod = traceMethod;
             this.traceCookie = traceCookie;
-            this.certificates = certificates;
+            this.signingDetails = signingDetails;
             this.installReason = installReason;
         }
 
@@ -15102,7 +15173,7 @@
                     params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
-                    params.traceMethod, params.traceCookie, params.certificates,
+                    params.traceMethod, params.traceCookie, params.signingDetails,
                     params.installReason);
             if (isFwdLocked()) {
                 throw new IllegalArgumentException("Forward locking only supported in ASEC");
@@ -15112,7 +15183,7 @@
         /** Existing install */
         FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
             super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
-                    null, null, null, 0, null /*certificates*/,
+                    null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
                     PackageManager.INSTALL_REASON_UNKNOWN);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
@@ -15333,7 +15404,7 @@
                     params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
-                    params.traceMethod, params.traceCookie, params.certificates,
+                    params.traceMethod, params.traceCookie, params.signingDetails,
                     params.installReason);
         }
 
@@ -15672,7 +15743,8 @@
                 }
             } else {
                 // default to original signature matching
-                if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
+                if (compareSignatures(oldPackage.mSigningDetails.signatures,
+                        pkg.mSigningDetails.signatures)
                         != PackageManager.SIGNATURE_MATCH) {
                     res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                             "New package has a different signature: " + pkgName);
@@ -16384,7 +16456,6 @@
                 | PackageParser.PARSE_ENFORCE_CODE
                 | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
                 | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
-                | (instantApp ? PackageParser.PARSE_IS_EPHEMERAL : 0)
                 | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
         PackageParser pp = new PackageParser();
         pp.setSeparateProcesses(mSeparateProcesses);
@@ -16412,19 +16483,29 @@
             return;
         }
 
-        // Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
-        if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
-            Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
-            res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
-                    "Instant app package must target O");
-            return;
-        }
-        if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
-            Slog.w(TAG, "Instant app package " + pkg.packageName
-                    + " does not target targetSandboxVersion 2");
-            res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
-                    "Instant app package must use targetSanboxVersion 2");
-            return;
+        // Instant apps have several additional install-time checks.
+        if (instantApp) {
+            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+                Slog.w(TAG,
+                        "Instant app package " + pkg.packageName + " does not target at least O");
+                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                        "Instant app package must target at least O");
+                return;
+            }
+            if (pkg.applicationInfo.targetSandboxVersion != 2) {
+                Slog.w(TAG, "Instant app package " + pkg.packageName
+                        + " does not target targetSandboxVersion 2");
+                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                        "Instant app package must use targetSandboxVersion 2");
+                return;
+            }
+            if (pkg.mSharedUserId != null) {
+                Slog.w(TAG, "Instant app package " + pkg.packageName
+                        + " may not declare sharedUserId.");
+                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                        "Instant app package may not declare a sharedUserId");
+                return;
+            }
         }
 
         if (pkg.applicationInfo.isStaticSharedLibrary()) {
@@ -16484,14 +16565,8 @@
 
         try {
             // either use what we've been given or parse directly from the APK
-            if (args.certificates != null) {
-                try {
-                    PackageParser.populateCertificates(pkg, args.certificates);
-                } catch (PackageParserException e) {
-                    // there was something wrong with the certificates we were given;
-                    // try to pull them from the APK
-                    PackageParser.collectCertificates(pkg, parseFlags);
-                }
+            if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
+                pkg.setSigningDetails(args.signingDetails);
             } else {
                 PackageParser.collectCertificates(pkg, parseFlags);
             }
@@ -16500,6 +16575,15 @@
             return;
         }
 
+        if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
+                < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+            Slog.w(TAG, "Instant app package " + pkg.packageName
+                    + " is not signed with at least APK Signature Scheme v2");
+            res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                    "Instant app package must be signed with APK Signature Scheme v2 or greater");
+            return;
+        }
+
         // Get rid of all references to package scan path via parser.
         pp = null;
         String oldCodePath = null;
@@ -16609,8 +16693,10 @@
                     try {
                         final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
                         final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+                        // We don't care about disabledPkgSetting on install for now.
                         final boolean compatMatch = verifySignatures(
-                                signatureCheckPs, pkg.mSignatures, compareCompat, compareRecover);
+                                signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
+                                compareRecover);
                         // The new KeySets will be re-added later in the scanning process.
                         if (compatMatch) {
                             synchronized (mPackages) {
@@ -16661,7 +16747,7 @@
                         sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
                     } else {
                         sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures,
-                                pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
+                                pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH;
                     }
                     if (!sigsOk) {
                         // If the owning package is the system itself, we log but allow
@@ -16937,7 +17023,8 @@
                 for (ActivityIntentInfo filter : a.intents) {
                     if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
-                            Slog.d(TAG, "Intent filter needs verification, so processing all filters");
+                            Slog.d(TAG,
+                                    "Intent filter needs verification, so processing all filters");
                         }
                         needToVerify = true;
                         break;
@@ -18267,7 +18354,8 @@
                     null /*enabledComponents*/,
                     null /*disabledComponents*/,
                     ps.readUserState(nextUserId).domainVerificationStatus,
-                    0, PackageManager.INSTALL_REASON_UNKNOWN);
+                    0, PackageManager.INSTALL_REASON_UNKNOWN,
+                    null /*harmfulAppWarning*/);
         }
         mSettings.writeKernelMappingLPr(ps);
     }
@@ -22245,8 +22333,8 @@
         final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
         final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
                 installerPackageName, volumeUuid, null /*verificationInfo*/, user,
-                packageAbiOverride, null /*grantedPermissions*/, null /*certificates*/,
-                PackageManager.INSTALL_REASON_UNKNOWN);
+                packageAbiOverride, null /*grantedPermissions*/,
+                PackageParser.SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN);
         params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -23579,6 +23667,47 @@
         }
         return unusedPackages;
     }
+
+    @Override
+    public void setHarmfulAppWarning(@NonNull String packageName, @Nullable CharSequence warning,
+            int userId) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingAppId = UserHandle.getAppId(callingUid);
+
+        mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+                true /*requireFullPermission*/, true /*checkShell*/, "setHarmfulAppInfo");
+
+        if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID &&
+                checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid) != PERMISSION_GRANTED) {
+            throw new SecurityException("Caller must have the "
+                    + SET_HARMFUL_APP_WARNINGS + " permission.");
+        }
+
+        synchronized(mPackages) {
+            mSettings.setHarmfulAppWarningLPw(packageName, warning, userId);
+            scheduleWritePackageRestrictionsLocked(userId);
+        }
+    }
+
+    @Nullable
+    @Override
+    public CharSequence getHarmfulAppWarning(@NonNull String packageName, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingAppId = UserHandle.getAppId(callingUid);
+
+        mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+                true /*requireFullPermission*/, true /*checkShell*/, "getHarmfulAppInfo");
+
+        if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID &&
+                checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid) != PERMISSION_GRANTED) {
+            throw new SecurityException("Caller must have the "
+                    + SET_HARMFUL_APP_WARNINGS + " permission.");
+        }
+
+        synchronized(mPackages) {
+            return mSettings.getHarmfulAppWarningLPr(packageName, userId);
+        }
+    }
 }
 
 interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 20ec9b5..7b96ca6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -33,10 +33,12 @@
 import com.android.server.pm.dex.PackageDexUsage;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppGlobals;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
 import android.os.Build;
@@ -45,6 +47,7 @@
 import android.os.FileUtils;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.service.pm.PackageServiceDumpProto;
 import android.system.ErrnoException;
@@ -504,13 +507,13 @@
      * system upgrade) and {@code scannedSigs} will be in the newer format.
      */
     private static boolean matchSignaturesCompat(String packageName,
-            PackageSignatures packageSignatures, Signature[] parsedSignatures) {
+            PackageSignatures packageSignatures, PackageParser.SigningDetails parsedSignatures) {
         ArraySet<Signature> existingSet = new ArraySet<Signature>();
         for (Signature sig : packageSignatures.mSignatures) {
             existingSet.add(sig);
         }
         ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
-        for (Signature sig : parsedSignatures) {
+        for (Signature sig : parsedSignatures.signatures) {
             try {
                 Signature[] chainSignatures = sig.getChainSignatures();
                 for (Signature chainSig : chainSignatures) {
@@ -547,27 +550,69 @@
     }
 
     /**
+     * Make sure the updated priv app is signed with the same key as the original APK file on the
+     * /system partition.
+     *
+     * <p>The rationale is that {@code disabledPkg} is a PackageSetting backed by xml files in /data
+     * and is not tamperproof.
+     */
+    private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
+            PackageSetting disabledPkgSetting) {
+        try {
+            PackageParser.collectCertificates(disabledPkgSetting.pkg,
+                    PackageParser.PARSE_IS_SYSTEM_DIR);
+            if (compareSignatures(pkgSetting.signatures.mSignatures,
+                        disabledPkgSetting.signatures.mSignatures)
+                    != PackageManager.SIGNATURE_MATCH) {
+                logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " +
+                        pkgSetting.name);
+                return false;
+            }
+        } catch (PackageParserException e) {
+            logCriticalInfo(Log.ERROR, "Failed to collect cert for " + pkgSetting.name + ": " +
+                    e.getMessage());
+            return false;
+        }
+        return true;
+    }
+
+    /** Returns true to force apk verification if the updated package (in /data) is a priv app. */
+    static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) {
+        return disabledPs != null && disabledPs.isPrivileged() &&
+                SystemProperties.getInt("ro.apk_verity.mode", 0) != 0;
+    }
+
+    /**
      * Verifies that signatures match.
      * @returns {@code true} if the compat signatures were matched; otherwise, {@code false}.
      * @throws PackageManagerException if the signatures did not match.
      */
     public static boolean verifySignatures(PackageSetting pkgSetting,
-            Signature[] parsedSignatures, boolean compareCompat, boolean compareRecover)
+            PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures,
+            boolean compareCompat, boolean compareRecover)
             throws PackageManagerException {
         final String packageName = pkgSetting.name;
         boolean compatMatch = false;
         if (pkgSetting.signatures.mSignatures != null) {
             // Already existing package. Make sure signatures match
-            boolean match = compareSignatures(pkgSetting.signatures.mSignatures, parsedSignatures)
+            boolean match = compareSignatures(pkgSetting.signatures.mSignatures,
+                    parsedSignatures.signatures)
                     == PackageManager.SIGNATURE_MATCH;
             if (!match && compareCompat) {
-                match = matchSignaturesCompat(packageName, pkgSetting.signatures, parsedSignatures);
+                match = matchSignaturesCompat(packageName, pkgSetting.signatures,
+                        parsedSignatures);
                 compatMatch = match;
             }
             if (!match && compareRecover) {
                 match = matchSignaturesRecover(
-                        packageName, pkgSetting.signatures.mSignatures, parsedSignatures);
+                        packageName, pkgSetting.signatures.mSignatures,
+                        parsedSignatures.signatures);
             }
+
+            if (!match && isApkVerificationForced(disabledPkgSetting)) {
+                match = matchSignatureInSystem(pkgSetting, disabledPkgSetting);
+            }
+
             if (!match) {
                 throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                         "Package " + packageName +
@@ -578,14 +623,14 @@
         if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
             // Already existing package. Make sure signatures match
             boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
-                    parsedSignatures) == PackageManager.SIGNATURE_MATCH;
+                    parsedSignatures.signatures) == PackageManager.SIGNATURE_MATCH;
             if (!match && compareCompat) {
                 match = matchSignaturesCompat(
                         packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
             }
             if (!match && compareRecover) {
-                match = matchSignaturesRecover(
-                        packageName, pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures);
+                match = matchSignaturesRecover(packageName,
+                        pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures.signatures);
                 compatMatch |= match;
             }
             if (!match) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 2d82c46..bd1cd33 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -230,6 +230,8 @@
                     return runGetInstantAppResolver();
                 case "has-feature":
                     return runHasFeature();
+                case "set-harmful-app-warning":
+                    return runSetHarmfulAppWarning();
                 default: {
                     String nextArg = getNextArg();
                     if (nextArg == null) {
@@ -1277,7 +1279,7 @@
             return runRemoveSplit(packageName, splitName);
         }
 
-        userId = translateUserId(userId, "runUninstall");
+        userId = translateUserId(userId, true /*allowAll*/, "runUninstall");
         if (userId == UserHandle.USER_ALL) {
             userId = UserHandle.USER_SYSTEM;
             flags |= PackageManager.DELETE_ALL_USERS;
@@ -2088,6 +2090,29 @@
         return 0;
     }
 
+    private int runSetHarmfulAppWarning() throws RemoteException {
+        int userId = UserHandle.USER_CURRENT;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                getErrPrintWriter().println("Error: Unknown option: " + opt);
+                return -1;
+            }
+        }
+
+        userId = translateUserId(userId, false /*allowAll*/, "runSetHarmfulAppWarning");
+
+        final String packageName = getNextArgRequired();
+        final String warning = getNextArg();
+
+        mInterface.setHarmfulAppWarning(packageName, warning, userId);
+
+        return 0;
+    }
+
     private static String checkAbiArgument(String abi) {
         if (TextUtils.isEmpty(abi)) {
             throw new IllegalArgumentException("Missing ABI argument");
@@ -2107,14 +2132,14 @@
         throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
     }
 
-    private int translateUserId(int userId, String logContext) {
+    private int translateUserId(int userId, boolean allowAll, String logContext) {
         return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, true, true, logContext, "pm command");
+                userId, allowAll, true, logContext, "pm command");
     }
 
     private int doCreateSession(SessionParams params, String installerPackageName, int userId)
             throws RemoteException {
-        userId = translateUserId(userId, "runInstallCreate");
+        userId = translateUserId(userId, true /*allowAll*/, "runInstallCreate");
         if (userId == UserHandle.USER_ALL) {
             userId = UserHandle.USER_SYSTEM;
             params.installFlags |= PackageManager.INSTALL_ALL_USERS;
@@ -2634,6 +2659,9 @@
         pw.println("");
         pw.println("  get-instantapp-resolver");
         pw.println("    Return the name of the component that is the current instant app installer.");
+        pw.println("");
+        pw.println("  set-harmful-app-warning [--user <USER_ID>] <PACKAGE> [<WARNING>]");
+        pw.println("    Mark the app as harmful with the given warning message.");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
     }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 2b91b7d..2a2430c 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -97,6 +97,35 @@
             + " " + name + "/" + appId + "}";
     }
 
+    // Temporary to catch potential issues with refactoring
+    public String dumpState_temp() {
+        String flags = "";
+        flags += ((pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ? "U" : "");
+        flags += ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 ? "S" : "");
+        if ("".equals(flags)) {
+            flags = "-";
+        }
+        String privFlags = "";
+        privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0 ? "P" : "");
+        privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0 ? "O" : "");
+        privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0 ? "V" : "");
+        if ("".equals(privFlags)) {
+            privFlags = "-";
+        }
+        return "PackageSetting{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + name + (realName == null ? "" : "("+realName+")") + "/" + appId + (sharedUser==null?"":" u:" + sharedUser.name+"("+sharedUserId+")")
+                + ", ver:" + versionCode
+                + ", path: " + codePath
+                + ", pABI: " + primaryCpuAbiString
+                + ", sABI: " + secondaryCpuAbiString
+                + ", oABI: " + cpuAbiOverrideString
+                + ", flags: " + flags
+                + ", privFlags: " + privFlags
+                + ", pkg: " + (pkg == null ? "<<NULL>>" : pkg.dumpState_temp())
+                + "}";
+    }
+
     public void copyFrom(PackageSetting orig) {
         super.copyFrom(orig);
         doCopy(orig);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 809e16c..e3c4c43 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -437,7 +437,8 @@
             boolean notLaunched, boolean hidden, boolean suspended, boolean instantApp,
             boolean virtualPreload, String lastDisableAppCaller,
             ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
-            int domainVerifState, int linkGeneration, int installReason) {
+            int domainVerifState, int linkGeneration, int installReason,
+            String harmfulAppWarning) {
         PackageUserState state = modifyUserState(userId);
         state.ceDataInode = ceDataInode;
         state.enabled = enabled;
@@ -454,6 +455,7 @@
         state.installReason = installReason;
         state.instantApp = instantApp;
         state.virtualPreload = virtualPreload;
+        state.harmfulAppWarning = harmfulAppWarning;
     }
 
     ArraySet<String> getEnabledComponents(int userId) {
@@ -620,4 +622,14 @@
             proto.end(userToken);
         }
     }
+
+    void setHarmfulAppWarning(int userId, String harmfulAppWarning) {
+        PackageUserState userState = modifyUserState(userId);
+        userState.harmfulAppWarning = harmfulAppWarning;
+    }
+
+    String getHarmfulAppWarning(int userId) {
+        PackageUserState userState = readUserState(userId);
+        return userState.harmfulAppWarning;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java
index f5c81e4..d567d5c 100644
--- a/services/core/java/com/android/server/pm/PackageSignatures.java
+++ b/services/core/java/com/android/server/pm/PackageSignatures.java
@@ -22,6 +22,8 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.Signature;
 import android.util.Log;
 
@@ -30,15 +32,17 @@
 
 class PackageSignatures {
     Signature[] mSignatures;
+    @SignatureSchemeVersion int mSignatureSchemeVersion;
 
     PackageSignatures(PackageSignatures orig) {
         if (orig != null && orig.mSignatures != null) {
             mSignatures = orig.mSignatures.clone();
+            mSignatureSchemeVersion = orig.mSignatureSchemeVersion;
         }
     }
 
-    PackageSignatures(Signature[] sigs) {
-        assignSignatures(sigs);
+    PackageSignatures(PackageParser.SigningDetails signingDetails) {
+        assignSignatures(signingDetails);
     }
 
     PackageSignatures() {
@@ -52,6 +56,7 @@
         serializer.startTag(null, tagName);
         serializer.attribute(null, "count",
                 Integer.toString(mSignatures.length));
+        serializer.attribute(null, "schemeVersion", Integer.toString(mSignatureSchemeVersion));
         for (int i=0; i<mSignatures.length; i++) {
             serializer.startTag(null, "cert");
             final Signature sig = mSignatures[i];
@@ -84,6 +89,15 @@
                        + " no count at " + parser.getPositionDescription());
             XmlUtils.skipCurrentTag(parser);
         }
+        String schemeVersionStr = parser.getAttributeValue(null, "schemeVersion");
+        if (schemeVersionStr == null) {
+            PackageManagerService.reportSettingsProblem(Log.WARN,
+                    "Error in package manager settings: <signatures> has no schemeVersion at "
+                        + parser.getPositionDescription());
+            mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN;
+        } else {
+            mSignatureSchemeVersion = Integer.parseInt(countStr);
+        }
         final int count = Integer.parseInt(countStr);
         mSignatures = new Signature[count];
         int pos = 0;
@@ -174,14 +188,15 @@
         }
     }
 
-    void assignSignatures(Signature[] sigs) {
-        if (sigs == null) {
+    void assignSignatures(PackageParser.SigningDetails signingDetails) {
+        mSignatureSchemeVersion = signingDetails.signatureSchemeVersion;
+        if (!signingDetails.hasSignatures()) {
             mSignatures = null;
             return;
         }
-        mSignatures = new Signature[sigs.length];
-        for (int i=0; i<sigs.length; i++) {
-            mSignatures[i] = sigs[i];
+        mSignatures = new Signature[signingDetails.signatures.length];
+        for (int i=0; i<signingDetails.signatures.length; i++) {
+            mSignatures[i] = signingDetails.signatures[i];
         }
     }
 
@@ -190,7 +205,9 @@
         StringBuffer buf = new StringBuffer(128);
         buf.append("PackageSignatures{");
         buf.append(Integer.toHexString(System.identityHashCode(this)));
-        buf.append(" [");
+        buf.append(" version:");
+        buf.append(mSignatureSchemeVersion);
+        buf.append(", signatures:[");
         if (mSignatures != null) {
             for (int i=0; i<mSignatures.length; i++) {
                 if (i > 0) buf.append(", ");
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index fbf3d82..2552643 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -17,9 +17,8 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
-import android.content.pm.SELinuxUtil;
 import android.content.pm.Signature;
+import android.content.pm.PackageParser.SigningDetails;
 import android.os.Environment;
 import android.util.Slog;
 import android.util.Xml;
@@ -453,7 +452,8 @@
     public String getMatchedSeInfo(PackageParser.Package pkg) {
         // Check for exact signature matches across all certs.
         Signature[] certs = mCerts.toArray(new Signature[0]);
-        if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
+        if (pkg.mSigningDetails != SigningDetails.UNKNOWN
+                && !Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) {
             return null;
         }
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 4cf1814..ecbc452 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -227,6 +227,7 @@
     private static final String ATTR_INSTALL_REASON = "install-reason";
     private static final String ATTR_INSTANT_APP = "instant-app";
     private static final String ATTR_VIRTUAL_PRELOAD = "virtual-preload";
+    private static final String ATTR_HARMFUL_APP_WARNING = "harmful-app-warning";
 
     private static final String ATTR_PACKAGE_NAME = "packageName";
     private static final String ATTR_FINGERPRINT = "fingerprint";
@@ -742,7 +743,8 @@
                                 null /*enabledComponents*/,
                                 null /*disabledComponents*/,
                                 INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
-                                0, PackageManager.INSTALL_REASON_UNKNOWN);
+                                0, PackageManager.INSTALL_REASON_UNKNOWN,
+                                null /*harmfulAppWarning*/);
                     }
                 }
             }
@@ -783,11 +785,12 @@
      */
     static void updatePackageSetting(@NonNull PackageSetting pkgSetting,
             @Nullable PackageSetting disabledPkg, @Nullable SharedUserSetting sharedUser,
-            @NonNull File codePath, @Nullable String legacyNativeLibraryPath,
-            @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi,
-            int pkgFlags, int pkgPrivateFlags, @Nullable List<String> childPkgNames,
-            @NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries,
-            @Nullable long[] usesStaticLibrariesVersions) throws PackageManagerException {
+            @NonNull File codePath, File resourcePath,
+            @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi,
+            @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags,
+            @Nullable List<String> childPkgNames, @NonNull UserManagerService userManager,
+            @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions)
+                    throws PackageManagerException {
         final String pkgName = pkgSetting.name;
         if (pkgSetting.sharedUser != sharedUser) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -799,29 +802,19 @@
         }
 
         if (!pkgSetting.codePath.equals(codePath)) {
-            // Check to see if its a disabled system app
-            if ((pkgSetting.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                // This is an updated system app with versions in both system
-                // and data partition. Just let the most recent version
-                // take precedence.
-                Slog.w(PackageManagerService.TAG,
-                        "Trying to update system app code path from "
-                        + pkgSetting.codePathString + " to " + codePath.toString());
-            } else {
-                // Just a change in the code path is not an issue, but
-                // let's log a message about it.
-                Slog.i(PackageManagerService.TAG,
-                        "Package " + pkgName + " codePath changed from "
-                        + pkgSetting.codePath + " to " + codePath
-                        + "; Retaining data and using new");
-
-                // The owner user's installed flag is set false
-                // when the application was installed by other user
-                // and the installed flag is not updated
-                // when the application is appended as system app later.
-                if ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0
-                        && disabledPkg == null) {
-                    List<UserInfo> allUserInfos = getAllUsers(userManager);
+            final boolean isSystem = pkgSetting.isSystem();
+            Slog.i(PackageManagerService.TAG,
+                    "Update" + (isSystem ? " system" : "")
+                    + " package " + pkgName
+                    + " code path from " + pkgSetting.codePathString
+                    + " to " + codePath.toString()
+                    + "; Retain data and using new");
+            if (!isSystem) {
+                // The package isn't considered as installed if the application was
+                // first installed by another user. Update the installed flag when the
+                // application ever becomes part of the system.
+                if ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 && disabledPkg == null) {
+                    final List<UserInfo> allUserInfos = getAllUsers(userManager);
                     if (allUserInfos != null) {
                         for (UserInfo userInfo : allUserInfos) {
                             pkgSetting.setInstalled(true, userInfo.id);
@@ -829,14 +822,24 @@
                     }
                 }
 
-                /*
-                 * Since we've changed paths, we need to prefer the new
-                 * native library path over the one stored in the
-                 * package settings since we might have moved from
-                 * internal to external storage or vice versa.
-                 */
+                // Since we've changed paths, prefer the new native library path over
+                // the one stored in the package settings since we might have moved from
+                // internal to external storage or vice versa.
                 pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
             }
+            pkgSetting.codePath = codePath;
+            pkgSetting.codePathString = codePath.toString();
+        }
+        if (!pkgSetting.resourcePath.equals(resourcePath)) {
+            final boolean isSystem = pkgSetting.isSystem();
+            Slog.i(PackageManagerService.TAG,
+                    "Update" + (isSystem ? " system" : "")
+                    + " package " + pkgName
+                    + " resource path from " + pkgSetting.resourcePathString
+                    + " to " + resourcePath.toString()
+                    + "; Retain data and using new");
+            pkgSetting.resourcePath = resourcePath;
+            pkgSetting.resourcePathString = resourcePath.toString();
         }
         // If what we are scanning is a system (and possibly privileged) package,
         // then make it so, regardless of whether it was previously installed only
@@ -853,13 +856,14 @@
         if (childPkgNames != null) {
             pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
         }
-        if (usesStaticLibraries != null) {
-            pkgSetting.usesStaticLibraries = Arrays.copyOf(usesStaticLibraries,
-                    usesStaticLibraries.length);
-        }
-        if (usesStaticLibrariesVersions != null) {
-            pkgSetting.usesStaticLibrariesVersions = Arrays.copyOf(usesStaticLibrariesVersions,
-                    usesStaticLibrariesVersions.length);
+        // Update static shared library dependencies if needed
+        if (usesStaticLibraries != null && usesStaticLibrariesVersions != null
+                && usesStaticLibraries.length == usesStaticLibrariesVersions.length) {
+            pkgSetting.usesStaticLibraries = usesStaticLibraries;
+            pkgSetting.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
+        } else {
+            pkgSetting.usesStaticLibraries = null;
+            pkgSetting.usesStaticLibrariesVersions = null;
         }
     }
 
@@ -912,69 +916,17 @@
                 userId);
     }
 
+    // TODO: Move to scanPackageOnlyLI() after verifying signatures are setup correctly
+    // by that time.
     void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
-        p.pkg = pkg;
-        // pkg.mSetEnabled = p.getEnabled(userId);
-        // pkg.mSetStopped = p.getStopped(userId);
-        final String volumeUuid = pkg.applicationInfo.volumeUuid;
-        final String codePath = pkg.applicationInfo.getCodePath();
-        final String resourcePath = pkg.applicationInfo.getResourcePath();
-        final String legacyNativeLibraryPath = pkg.applicationInfo.nativeLibraryRootDir;
-        // Update volume if needed
-        if (!Objects.equals(volumeUuid, p.volumeUuid)) {
-            Slog.w(PackageManagerService.TAG, "Volume for " + p.pkg.packageName +
-                    " changing from " + p.volumeUuid + " to " + volumeUuid);
-            p.volumeUuid = volumeUuid;
-        }
-        // Update code path if needed
-        if (!Objects.equals(codePath, p.codePathString)) {
-            Slog.w(PackageManagerService.TAG, "Code path for " + p.pkg.packageName +
-                    " changing from " + p.codePathString + " to " + codePath);
-            p.codePath = new File(codePath);
-            p.codePathString = codePath;
-        }
-        //Update resource path if needed
-        if (!Objects.equals(resourcePath, p.resourcePathString)) {
-            Slog.w(PackageManagerService.TAG, "Resource path for " + p.pkg.packageName +
-                    " changing from " + p.resourcePathString + " to " + resourcePath);
-            p.resourcePath = new File(resourcePath);
-            p.resourcePathString = resourcePath;
-        }
-        // Update the native library paths if needed
-        if (!Objects.equals(legacyNativeLibraryPath, p.legacyNativeLibraryPathString)) {
-            p.legacyNativeLibraryPathString = legacyNativeLibraryPath;
-        }
-
-        // Update the required Cpu Abi
-        p.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
-        p.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
-        p.cpuAbiOverrideString = pkg.cpuAbiOverride;
-        // Update version code if needed
-        if (pkg.getLongVersionCode() != p.versionCode) {
-            p.versionCode = pkg.getLongVersionCode();
-        }
         // Update signatures if needed.
         if (p.signatures.mSignatures == null) {
-            p.signatures.assignSignatures(pkg.mSignatures);
-        }
-        // Update flags if needed.
-        if (pkg.applicationInfo.flags != p.pkgFlags) {
-            p.pkgFlags = pkg.applicationInfo.flags;
+            p.signatures.assignSignatures(pkg.mSigningDetails);
         }
         // If this app defines a shared user id initialize
         // the shared user signatures as well.
         if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
-            p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
-        }
-        // Update static shared library dependencies if needed
-        if (pkg.usesStaticLibraries != null && pkg.usesStaticLibrariesVersions != null
-                && pkg.usesStaticLibraries.size() == pkg.usesStaticLibrariesVersions.length) {
-            p.usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
-            pkg.usesStaticLibraries.toArray(p.usesStaticLibraries);
-            p.usesStaticLibrariesVersions = pkg.usesStaticLibrariesVersions;
-        } else {
-            p.usesStaticLibraries = null;
-            p.usesStaticLibrariesVersions = null;
+            p.sharedUser.signatures.assignSignatures(pkg.mSigningDetails);
         }
         addPackageSettingLPw(p, p.sharedUser);
     }
@@ -1680,7 +1632,8 @@
                                 null /*enabledComponents*/,
                                 null /*disabledComponents*/,
                                 INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
-                                0, PackageManager.INSTALL_REASON_UNKNOWN);
+                                0, PackageManager.INSTALL_REASON_UNKNOWN,
+                                null /*harmfulAppWarning*/);
                     }
                     return;
                 }
@@ -1755,7 +1708,8 @@
                             COMPONENT_ENABLED_STATE_DEFAULT);
                     final String enabledCaller = parser.getAttributeValue(null,
                             ATTR_ENABLED_CALLER);
-
+                    final String harmfulAppWarning =
+                            parser.getAttributeValue(null, ATTR_HARMFUL_APP_WARNING);
                     final int verifState = XmlUtils.readIntAttribute(parser,
                             ATTR_DOMAIN_VERIFICATON_STATE,
                             PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
@@ -1792,7 +1746,7 @@
                     ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
                             hidden, suspended, instantApp, virtualPreload, enabledCaller,
                             enabledComponents, disabledComponents, verifState, linkGeneration,
-                            installReason);
+                            installReason, harmfulAppWarning);
                 } else if (tagName.equals("preferred-activities")) {
                     readPreferredActivitiesLPw(parser, userId);
                 } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -2125,6 +2079,10 @@
                     serializer.attribute(null, ATTR_INSTALL_REASON,
                             Integer.toString(ustate.installReason));
                 }
+                if (ustate.harmfulAppWarning != null) {
+                    serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
+                            ustate.harmfulAppWarning);
+                }
                 if (!ArrayUtils.isEmpty(ustate.enabledComponents)) {
                     serializer.startTag(null, TAG_ENABLED_COMPONENTS);
                     for (final String name : ustate.enabledComponents) {
@@ -4347,6 +4305,22 @@
         return false;
     }
 
+    void setHarmfulAppWarningLPw(String packageName, CharSequence warning, int userId) {
+        final PackageSetting pkgSetting = mPackages.get(packageName);
+        if (pkgSetting == null) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+        pkgSetting.setHarmfulAppWarning(userId, warning == null ? null : warning.toString());
+    }
+
+    String getHarmfulAppWarningLPr(String packageName, int userId) {
+        final PackageSetting pkgSetting = mPackages.get(packageName);
+        if (pkgSetting == null) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+        return pkgSetting.getHarmfulAppWarning(userId);
+    }
+
     private static List<UserInfo> getAllUsers(UserManagerService userManager) {
         long id = Binder.clearCallingIdentity();
         try {
@@ -4493,11 +4467,14 @@
                 pw.print(ps.getNotLaunched(user.id) ? "l" : "L");
                 pw.print(ps.getInstantApp(user.id) ? "IA" : "ia");
                 pw.print(ps.getVirtulalPreload(user.id) ? "VPI" : "vpi");
+                String harmfulAppWarning = ps.getHarmfulAppWarning(user.id);
+                pw.print(harmfulAppWarning != null ? "HA" : "ha");
                 pw.print(",");
                 pw.print(ps.getEnabled(user.id));
                 String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
                 pw.print(",");
                 pw.print(lastDisabledAppCaller != null ? lastDisabledAppCaller : "?");
+                pw.print(",");
                 pw.println();
             }
             return;
@@ -4565,10 +4542,8 @@
             }
             pw.print(prefix); pw.print("  versionName="); pw.println(ps.pkg.mVersionName);
             pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, ps.pkg); pw.println();
-            final int apkSigningVersion = PackageParser.getApkSigningVersion(ps.pkg);
-            if (apkSigningVersion != PackageParser.APK_SIGNING_UNKNOWN) {
-                pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
-            }
+            final int apkSigningVersion = ps.pkg.mSigningDetails.signatureSchemeVersion;
+            pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
             pw.print(prefix); pw.print("  applicationInfo=");
                 pw.println(ps.pkg.applicationInfo.toString());
             pw.print(prefix); pw.print("  flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
@@ -4772,6 +4747,12 @@
                         .getRuntimePermissionStates(user.id), dumpAll);
             }
 
+            String harmfulAppWarning = ps.getHarmfulAppWarning(user.id);
+            if (harmfulAppWarning != null) {
+                pw.print(prefix); pw.print("      harmfulAppWarning: ");
+                pw.println(harmfulAppWarning);
+            }
+
             if (permissionNames == null) {
                 ArraySet<String> cmp = ps.getDisabledComponents(user.id);
                 if (cmp != null && cmp.size() > 0) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 065eafd..d2bc6d2 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -396,7 +396,7 @@
     private final long[] mDurationStats = new long[Stats.COUNT];
 
     private static final int PROCESS_STATE_FOREGROUND_THRESHOLD =
-            ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+            ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 
     static final int OPERATION_SET = 0;
     static final int OPERATION_ADD = 1;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 7d57566..92fd904 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -394,7 +394,7 @@
     /**
      * Start an {@link IntentSender} when user is unlocked after disabling quiet mode.
      *
-     * @see {@link #trySetQuietModeEnabled(String, boolean, int, IntentSender)}
+     * @see {@link #requestQuietModeEnabled(String, boolean, int, IntentSender)}
      */
     private class DisableQuietModeUserUnlockedCallback extends IProgressListener.Stub {
         private final IntentSender mTarget;
@@ -823,7 +823,7 @@
     }
 
     @Override
-    public boolean trySetQuietModeEnabled(@NonNull String callingPackage, boolean enableQuietMode,
+    public boolean requestQuietModeEnabled(@NonNull String callingPackage, boolean enableQuietMode,
             int userHandle, @Nullable IntentSender target) {
         Preconditions.checkNotNull(callingPackage);
 
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index bfba700..cc07d82 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -25,12 +25,14 @@
 import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
@@ -116,7 +118,11 @@
             UserManager.DISALLOW_USER_SWITCH,
             UserManager.DISALLOW_UNIFIED_PASSWORD,
             UserManager.DISALLOW_CONFIG_LOCATION_MODE,
-            UserManager.DISALLOW_AIRPLANE_MODE
+            UserManager.DISALLOW_AIRPLANE_MODE,
+            UserManager.DISALLOW_CONFIG_BRIGHTNESS,
+            UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,
+            UserManager.DISALLOW_AMBIENT_DISPLAY,
+            UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT
     });
 
     /**
@@ -539,6 +545,22 @@
                             android.provider.Settings.Global.SAFE_BOOT_DISALLOWED,
                             newValue ? 1 : 0);
                     break;
+                case UserManager.DISALLOW_AIRPLANE_MODE:
+                    if (newValue) {
+                        final boolean airplaneMode = Settings.Global.getInt(
+                                context.getContentResolver(),
+                                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+                        if (airplaneMode) {
+                            android.provider.Settings.Global.putInt(
+                                    context.getContentResolver(),
+                                    android.provider.Settings.Global.AIRPLANE_MODE_ON, 0);
+                            // Post the intent.
+                            Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+                            intent.putExtra("state", 0);
+                            context.sendBroadcastAsUser(intent, UserHandle.ALL);
+                        }
+                    }
+                    break;
             }
         } finally {
             Binder.restoreCallingIdentity(id);
diff --git a/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java
index d6281c5..a517d6d 100644
--- a/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java
@@ -111,6 +111,7 @@
 
         final long ident = mInjector.clearCallingIdentity();
         try {
+            launchIntent.setPackage(null);
             launchIntent.setComponent(component);
             mContext.startActivityAsUser(launchIntent,
                     ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(), user);
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 34c3ce3..6e07eaa 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -27,7 +27,6 @@
 import android.companion.CompanionDeviceManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageList;
@@ -62,8 +61,6 @@
 import android.util.Xml;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
-import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.PackageSetting;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -1169,7 +1166,8 @@
         final String systemPackageName = mServiceInternal.getKnownPackageName(
                 PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
         final PackageParser.Package systemPackage = getPackage(systemPackageName);
-        return compareSignatures(systemPackage.mSignatures, pkg.mSignatures)
+        return compareSignatures(systemPackage.mSigningDetails.signatures,
+                pkg.mSigningDetails.signatures)
                 == PackageManager.SIGNATURE_MATCH;
     }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 90ac4ab..786b998 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -29,7 +29,6 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -56,21 +55,17 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
-import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.RoSystemProperties;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
-import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.PackageManagerServiceUtils;
 import com.android.server.pm.PackageSetting;
-import com.android.server.pm.ProcessLoggingHandler;
 import com.android.server.pm.SharedUserSetting;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
@@ -1015,10 +1010,10 @@
         final PackageParser.Package systemPackage =
                 mPackageManagerInt.getPackage(systemPackageName);
         boolean allowed = (PackageManagerServiceUtils.compareSignatures(
-                                bp.getSourceSignatures(), pkg.mSignatures)
+                                bp.getSourceSignatures(), pkg.mSigningDetails.signatures)
                         == PackageManager.SIGNATURE_MATCH)
                 || (PackageManagerServiceUtils.compareSignatures(
-                                systemPackage.mSignatures, pkg.mSignatures)
+                systemPackage.mSigningDetails.signatures, pkg.mSigningDetails.signatures)
                         == PackageManager.SIGNATURE_MATCH);
         if (!allowed && (privilegedPermission || oemPermission)) {
             if (pkg.isSystem()) {
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index 10d9565..c906705 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -16,13 +16,16 @@
 
 package com.android.server.policy;
 
+import static com.android.server.wm.proto.BarControllerProto.STATE;
+import static com.android.server.wm.proto.BarControllerProto.TRANSIENT_STATE;
+
 import android.app.StatusBarManager;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.WindowManager;
 
 import com.android.server.LocalServices;
@@ -311,6 +314,13 @@
         throw new IllegalArgumentException("Unknown state " + state);
     }
 
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(STATE, mState);
+        proto.write(TRANSIENT_STATE, mTransientBarState);
+        proto.end(token);
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         if (mWin != null) {
             pw.print(prefix); pw.println(mTag);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 076c0e4..a453c33 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -48,7 +48,6 @@
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
@@ -65,6 +64,9 @@
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
@@ -127,6 +129,26 @@
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.FOCUSED_APP_TOKEN;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.FOCUSED_WINDOW;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.FORCE_STATUS_BAR;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.FORCE_STATUS_BAR_FROM_KEYGUARD;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_DRAW_COMPLETE;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_OCCLUDED;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_OCCLUDED_CHANGED;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_OCCLUDED_PENDING;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.LAST_SYSTEM_UI_FLAGS;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.NAVIGATION_BAR;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.ORIENTATION;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.ORIENTATION_LISTENER;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.ROTATION;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.ROTATION_MODE;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.SCREEN_ON_FULLY;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.STATUS_BAR;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.TOP_FULLSCREEN_OPAQUE_OR_DIMMING_WINDOW;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.TOP_FULLSCREEN_OPAQUE_WINDOW;
+import static com.android.server.wm.proto.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -141,6 +163,7 @@
 import android.app.UiModeManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
+import android.content.ComponentCallbacks;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -172,7 +195,6 @@
 import android.media.IAudioService;
 import android.media.session.MediaSessionLegacyHelper;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.FactoryTest;
 import android.os.Handler;
@@ -247,9 +269,11 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
+import com.android.internal.policy.KeyguardDismissCallback;
 import com.android.internal.policy.PhoneWindow;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.widget.PointerLocationView;
 import com.android.server.GestureLauncherService;
@@ -441,6 +465,7 @@
     AccessibilityManager mAccessibilityManager;
     BurnInProtectionHelper mBurnInProtectionHelper;
     AppOpsManager mAppOpsManager;
+    private ScreenshotHelper mScreenshotHelper;
     private boolean mHasFeatureWatch;
     private boolean mHasFeatureLeanback;
 
@@ -469,6 +494,7 @@
     WindowState mNavigationBar = null;
     boolean mHasNavigationBar = false;
     boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side?
+    @NavigationBarPosition
     int mNavigationBarPosition = NAV_BAR_BOTTOM;
     int[] mNavigationBarHeightForRotationDefault = new int[4];
     int[] mNavigationBarWidthForRotationDefault = new int[4];
@@ -601,8 +627,6 @@
 
     PointerLocationView mPointerLocationView;
 
-    boolean mEmulateDisplayCutout = false;
-
     // During layout, the layer at which the doc window is placed.
     int mDockLayer;
     // During layout, this is the layer of the status bar.
@@ -698,6 +722,9 @@
     // Behavior of Back button while in-call and screen on
     int mIncallBackBehavior;
 
+    // Behavior of rotation suggestions. (See Settings.Secure.SHOW_ROTATION_SUGGESTION)
+    int mShowRotationSuggestions;
+
     Display mDisplay;
 
     int mLandscapeRotation = 0;  // default landscape rotation
@@ -952,11 +979,11 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this,
                     UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.POLICY_CONTROL), false, this,
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.EMULATE_DISPLAY_CUTOUT), false, this,
+                    Settings.Global.POLICY_CONTROL), false, this,
                     UserHandle.USER_ALL);
             updateSettings();
         }
@@ -985,23 +1012,41 @@
     }
 
     class MyOrientationListener extends WindowOrientationListener {
-        private final Runnable mUpdateRotationRunnable = new Runnable() {
+
+        private SparseArray<Runnable> mRunnableCache;
+
+        MyOrientationListener(Context context, Handler handler) {
+            super(context, handler);
+            mRunnableCache = new SparseArray<>(5);
+        }
+
+        private class UpdateRunnable implements Runnable {
+            private final int mRotation;
+            UpdateRunnable(int rotation) {
+                mRotation = rotation;
+            }
+
             @Override
             public void run() {
                 // send interaction hint to improve redraw performance
                 mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
-                updateRotation(false);
+                if (showRotationChoice(mCurrentAppOrientation, mRotation)) {
+                    sendProposedRotationChangeToStatusBarInternal(mRotation);
+                } else {
+                    updateRotation(false);
+                }
             }
-        };
-
-        MyOrientationListener(Context context, Handler handler) {
-            super(context, handler);
         }
 
         @Override
         public void onProposedRotationChanged(int rotation) {
             if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
-            mHandler.post(mUpdateRotationRunnable);
+            Runnable r = mRunnableCache.get(rotation, null);
+            if (r == null){
+                r = new UpdateRunnable(rotation);
+                mRunnableCache.put(rotation, r);
+            }
+            mHandler.post(r);
         }
     }
     MyOrientationListener mOrientationListener;
@@ -1106,7 +1151,11 @@
             // orientation for a little bit, which can cause orientation
             // changes to lag, so we'd like to keep it always on.  (It will
             // still be turned off when the screen is off.)
-            return false;
+
+            // When locked we can provide rotation suggestions users can approve to change the
+            // current screen rotation. To do this the sensor needs to be running.
+            return mSupportAutoRotation &&
+                    mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED;
         }
         return mSupportAutoRotation;
     }
@@ -1665,7 +1714,9 @@
 
         @Override
         public void run() {
-            takeScreenshot(mScreenshotType);
+            mScreenshotHelper.takeScreenshot(mScreenshotType,
+                    mStatusBar != null && mStatusBar.isVisibleLw(),
+                    mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler);
         }
     }
 
@@ -2143,6 +2194,7 @@
                         mWindowManagerFuncs.notifyKeyguardTrustedChanged();
                     }
                 });
+        mScreenshotHelper = new ScreenshotHelper(mContext);
     }
 
     /**
@@ -2255,9 +2307,13 @@
         // http://developer.android.com/guide/practices/screens_support.html#range
         // For car, ignore the dp limitation. It's physically impossible to rotate the car's screen
         // so if the orientation is forced, we need to respect that no matter what.
-        boolean isCar = mContext.getPackageManager().hasSystemFeature(
+        final boolean isCar = mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_AUTOMOTIVE);
-        mForceDefaultOrientation = ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar) &&
+        // For TV, it's usually 960dp x 540dp, ignore the size limitation.
+        // so if the orientation is forced, we need to respect that no matter what.
+        final boolean isTv = mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_LEANBACK);
+        mForceDefaultOrientation = ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv) &&
                 res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation) &&
                 // For debug purposes the next line turns this feature off with:
                 // $ adb shell setprop config.override_forced_orient true
@@ -2295,6 +2351,16 @@
                     Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR_DEFAULT,
                     UserHandle.USER_CURRENT);
 
+            // Configure rotation suggestions.
+            int showRotationSuggestions = Settings.Secure.getIntForUser(resolver,
+                    Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
+                    Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
+                    UserHandle.USER_CURRENT);
+            if (mShowRotationSuggestions != showRotationSuggestions) {
+                mShowRotationSuggestions = showRotationSuggestions;
+                updateOrientationListenerLp(); // Enable, disable the orientation listener
+            }
+
             // Configure wake gesture.
             boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
                     Settings.Secure.WAKE_GESTURE_ENABLED, 0,
@@ -2344,10 +2410,6 @@
             if (mImmersiveModeConfirmation != null) {
                 mImmersiveModeConfirmation.loadSetting(mCurrentUserId);
             }
-            mEmulateDisplayCutout = Settings.Global.getInt(resolver,
-                    Settings.Global.EMULATE_DISPLAY_CUTOUT,
-                    Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF)
-                    != Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF;
         }
         synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
             PolicyControl.reloadFromSetting(mContext);
@@ -2683,6 +2745,11 @@
     }
 
     @Override
+    public void onOverlayChangedLw() {
+        onConfigurationChanged();
+    }
+
+    @Override
     public void onConfigurationChanged() {
         // TODO(multi-display): Define policy for secondary displays.
         Context uiContext = getSystemUiContext();
@@ -4145,20 +4212,23 @@
             if (isKeyguardShowingAndNotOccluded()) {
                 // don't launch home if keyguard showing
                 return;
-            }
-
-            if (!mKeyguardOccluded && mKeyguardDelegate.isInputRestricted()) {
+            } else if (mKeyguardOccluded && mKeyguardDelegate.isShowing()) {
+                mKeyguardDelegate.dismiss(new KeyguardDismissCallback() {
+                    @Override
+                    public void onDismissSucceeded() throws RemoteException {
+                        mHandler.post(() -> {
+                            startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
+                        });
+                    }
+                }, null /* message */);
+                return;
+            } else if (!mKeyguardOccluded && mKeyguardDelegate.isInputRestricted()) {
                 // when in keyguard restricted mode, must first verify unlock
                 // before launching home
                 mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
                     @Override
                     public void onKeyguardExitResult(boolean success) {
                         if (success) {
-                            try {
-                                ActivityManager.getService().stopAppSwitches();
-                            } catch (RemoteException e) {
-                            }
-                            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
                             startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
                         }
                     }
@@ -4168,11 +4238,11 @@
         }
 
         // no keyguard stuff to worry about, just launch home!
-        try {
-            ActivityManager.getService().stopAppSwitches();
-        } catch (RemoteException e) {
-        }
         if (mRecentsVisible) {
+            try {
+                ActivityManager.getService().stopAppSwitches();
+            } catch (RemoteException e) {}
+
             // Hide Recents and notify it to launch Home
             if (awakenFromDreams) {
                 awakenDreams();
@@ -4180,7 +4250,6 @@
             hideRecentApps(false, true);
         } else {
             // Otherwise, just launch Home
-            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
             startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
         }
     }
@@ -4382,7 +4451,7 @@
     /** {@inheritDoc} */
     @Override
     public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
-        displayFrames.onBeginLayout(mEmulateDisplayCutout, mStatusBarHeight);
+        displayFrames.onBeginLayout();
         // TODO(multi-display): This doesn't seem right...Maybe only apply to default display?
         mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
         mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
@@ -4564,6 +4633,7 @@
             dockFrame.top = displayFrames.mStable.top;
             displayFrames.mContent.set(dockFrame);
             displayFrames.mVoiceContent.set(dockFrame);
+            displayFrames.mCurrent.set(dockFrame);
 
             if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
                     "dock=%s content=%s cur=%s", dockFrame.toString(),
@@ -4684,6 +4754,7 @@
         return mNavigationBarController.checkHiddenLw();
     }
 
+    @NavigationBarPosition
     private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
         if (mNavigationBarCanMove && displayWidth > displayHeight) {
             if (displayRotation == Surface.ROTATION_270) {
@@ -4801,7 +4872,6 @@
 
         final int type = attrs.type;
         final int fl = PolicyControl.getWindowFlags(win, attrs);
-        final long fl2 = attrs.flags2;
         final int pfl = attrs.privateFlags;
         final int sim = attrs.softInputMode;
         final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(win, null);
@@ -4823,12 +4893,10 @@
         final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
 
         final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
-                || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
-                || (requestedSysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0;
+                || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
 
         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
         final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
-        final boolean layoutInCutout = (fl2 & FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA) != 0;
 
         sf.set(displayFrames.mStable);
 
@@ -4988,9 +5056,6 @@
                         // moving from a window that is not hiding the status bar to one that is.
                         cf.set(displayFrames.mRestricted);
                     }
-                    if (requestedFullscreen && !layoutInCutout) {
-                        pf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
-                    }
                     applyStableConstraints(sysUiFl, fl, cf, displayFrames);
                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                         vf.set(displayFrames.mCurrent);
@@ -5076,9 +5141,6 @@
                     of.set(displayFrames.mUnrestricted);
                     df.set(displayFrames.mUnrestricted);
                     pf.set(displayFrames.mUnrestricted);
-                    if (requestedFullscreen && !layoutInCutout) {
-                        pf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
-                    }
                 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
                     of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
@@ -5153,15 +5215,18 @@
             }
         }
 
-        // Ensure that windows that did not request to be laid out in the cutout don't get laid
-        // out there.
-        if (!layoutInCutout) {
+        final int cutoutMode = attrs.layoutInDisplayCutoutMode;
+        // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
+        // the cutout safe zone.
+        if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
             final Rect displayCutoutSafeExceptMaybeTop = mTmpRect;
             displayCutoutSafeExceptMaybeTop.set(displayFrames.mDisplayCutoutSafe);
-            if (layoutInScreen && layoutInsetDecor) {
+            if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
+                    && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
                 // At the top we have the status bar, so apps that are
-                // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR already expect that there's an inset
-                // there and we don't need to exclude the window from that area.
+                // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
+                // already expect that there's an inset there and we don't need to exclude
+                // the window from that area.
                 displayCutoutSafeExceptMaybeTop.top = Integer.MIN_VALUE;
             }
             pf.intersectUnchecked(displayCutoutSafeExceptMaybeTop);
@@ -5706,100 +5771,6 @@
         setHdmiPlugged(!mHdmiPlugged);
     }
 
-    final Object mScreenshotLock = new Object();
-    ServiceConnection mScreenshotConnection = null;
-
-    final Runnable mScreenshotTimeout = new Runnable() {
-        @Override public void run() {
-            synchronized (mScreenshotLock) {
-                if (mScreenshotConnection != null) {
-                    mContext.unbindService(mScreenshotConnection);
-                    mScreenshotConnection = null;
-                    notifyScreenshotError();
-                }
-            }
-        }
-    };
-
-    // Assume this is called from the Handler thread.
-    private void takeScreenshot(final int screenshotType) {
-        synchronized (mScreenshotLock) {
-            if (mScreenshotConnection != null) {
-                return;
-            }
-            final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE,
-                    SYSUI_SCREENSHOT_SERVICE);
-            final Intent serviceIntent = new Intent();
-            serviceIntent.setComponent(serviceComponent);
-            ServiceConnection conn = new ServiceConnection() {
-                @Override
-                public void onServiceConnected(ComponentName name, IBinder service) {
-                    synchronized (mScreenshotLock) {
-                        if (mScreenshotConnection != this) {
-                            return;
-                        }
-                        Messenger messenger = new Messenger(service);
-                        Message msg = Message.obtain(null, screenshotType);
-                        final ServiceConnection myConn = this;
-                        Handler h = new Handler(mHandler.getLooper()) {
-                            @Override
-                            public void handleMessage(Message msg) {
-                                synchronized (mScreenshotLock) {
-                                    if (mScreenshotConnection == myConn) {
-                                        mContext.unbindService(mScreenshotConnection);
-                                        mScreenshotConnection = null;
-                                        mHandler.removeCallbacks(mScreenshotTimeout);
-                                    }
-                                }
-                            }
-                        };
-                        msg.replyTo = new Messenger(h);
-                        msg.arg1 = msg.arg2 = 0;
-                        if (mStatusBar != null && mStatusBar.isVisibleLw())
-                            msg.arg1 = 1;
-                        if (mNavigationBar != null && mNavigationBar.isVisibleLw())
-                            msg.arg2 = 1;
-                        try {
-                            messenger.send(msg);
-                        } catch (RemoteException e) {
-                        }
-                    }
-                }
-
-                @Override
-                public void onServiceDisconnected(ComponentName name) {
-                    synchronized (mScreenshotLock) {
-                        if (mScreenshotConnection != null) {
-                            mContext.unbindService(mScreenshotConnection);
-                            mScreenshotConnection = null;
-                            mHandler.removeCallbacks(mScreenshotTimeout);
-                            notifyScreenshotError();
-                        }
-                    }
-                }
-            };
-            if (mContext.bindServiceAsUser(serviceIntent, conn,
-                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
-                    UserHandle.CURRENT)) {
-                mScreenshotConnection = conn;
-                mHandler.postDelayed(mScreenshotTimeout, 10000);
-            }
-        }
-    }
-
-    /**
-     * Notifies the screenshot service to show an error.
-     */
-    private void notifyScreenshotError() {
-        // If the service process is killed, then ask it to clean up after itself
-        final ComponentName errorComponent = new ComponentName(SYSUI_PACKAGE,
-                SYSUI_SCREENSHOT_ERROR_RECEIVER);
-        Intent errorIntent = new Intent(Intent.ACTION_USER_PRESENT);
-        errorIntent.setComponent(errorComponent);
-        errorIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
-                Intent.FLAG_RECEIVER_FOREGROUND);
-        mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT);
-    }
 
     /** {@inheritDoc} */
     @Override
@@ -6224,6 +6195,16 @@
     }
 
     /**
+     * Notify the StatusBar that system rotation suggestion has changed.
+     */
+    private void sendProposedRotationChangeToStatusBarInternal(int rotation) {
+        StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+        if (statusBar != null) {
+            statusBar.onProposedRotationChanged(rotation);
+        }
+    }
+
+    /**
      * Returns true if the key can have global actions attached to it.
      * We reserve all power management keys for the system since they require
      * very careful handling.
@@ -6878,12 +6859,12 @@
     }
 
     @Override
-    public void dismissKeyguardLw(IKeyguardDismissCallback callback) {
+    public void dismissKeyguardLw(IKeyguardDismissCallback callback, CharSequence message) {
         if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw");
 
             // ask the keyguard to prompt the user to authenticate if necessary
-            mKeyguardDelegate.dismiss(callback);
+            mKeyguardDelegate.dismiss(callback, message);
         } else if (callback != null) {
             try {
                 callback.onDismissError();
@@ -7165,6 +7146,86 @@
         mOrientationListener.setCurrentRotation(rotation);
     }
 
+    public boolean showRotationChoice(int orientation, final int preferredRotation) {
+        // Rotation choice is only shown when the user is in locked mode.
+        if (mUserRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) return false;
+
+        // We should only show a rotation choice if:
+        // 1. The rotation isn't forced by the lid, dock, demo, hdmi, vr, etc mode
+        // 2. The user choice won't be ignored due to screen orientation settings
+
+        // Determine if the rotation currently forced
+        if (mForceDefaultOrientation) {
+            return false; // Rotation is forced to default orientation
+
+        } else if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {
+            return false; // Rotation is forced mLidOpenRotation
+
+        } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && !mCarDockEnablesAccelerometer) {
+            return false; // Rotation forced to mCarDockRotation
+
+        } else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+                || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
+                || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
+                && !mDeskDockEnablesAccelerometer) {
+            return false; // Rotation forced to mDeskDockRotation
+
+        } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
+            return false; // Rotation forced to mDemoHdmiRotation
+
+        } else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
+                && mUndockedHdmiRotation >= 0) {
+            return false; // Rotation forced to mUndockedHdmiRotation
+
+        } else if (mDemoRotationLock) {
+            return false; // Rotation forced to mDemoRotation
+
+        } else if (mPersistentVrModeEnabled) {
+            return false; // Rotation forced to mPortraitRotation
+
+        } else if (!mSupportAutoRotation) {
+            return false;
+        }
+
+        // Determine if the orientation will ignore user choice
+        switch (orientation) {
+            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
+            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
+            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+            case ActivityInfo.SCREEN_ORIENTATION_LOCKED:
+                return false; // Forced into a particular rotation, no user choice
+
+            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+            case ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR:
+            case ActivityInfo.SCREEN_ORIENTATION_SENSOR:
+                return false; // Sensor overrides user choice
+
+            case ActivityInfo.SCREEN_ORIENTATION_NOSENSOR:
+                // TODO Can sensor be used to indirectly determine the orientation?
+                return false;
+
+            case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
+                // If the user has locked sensor-based rotation, this behaves the same as landscape
+                return false; // User has locked the rotation, will behave as LANDSCAPE
+            case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
+                // If the user has locked sensor-based rotation, this behaves the same as portrait
+                return false; // User has locked the rotation, will behave as PORTRAIT
+            case ActivityInfo.SCREEN_ORIENTATION_USER:
+                // Works with any rotation except upside down
+                return (preferredRotation >= 0) && (preferredRotation != mUpsideDownRotation);
+            case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
+                // Works with any of the 4 rotations
+                return preferredRotation >= 0;
+
+            default:
+                // TODO: how to handle SCREEN_ORIENTATION_BEHIND, UNSET?
+                // For UNSPECIFIED use preferred orientation matching SCREEN_ORIENTATION_USER
+                return (preferredRotation >= 0) && (preferredRotation != mUpsideDownRotation);
+        }
+    }
+
     private boolean isLandscapeOrSeascape(int rotation) {
         return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
     }
@@ -7575,6 +7636,11 @@
     }
 
     void startDockOrHome(boolean fromHomeKey, boolean awakenFromDreams) {
+        try {
+            ActivityManager.getService().stopAppSwitches();
+        } catch (RemoteException e) {}
+        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+
         if (awakenFromDreams) {
             awakenDreams();
         }
@@ -7614,11 +7680,6 @@
         }
         if (false) {
             // This code always brings home to the front.
-            try {
-                ActivityManager.getService().stopAppSwitches();
-            } catch (RemoteException e) {
-            }
-            sendCloseSystemWindows();
             startDockOrHome(false /*fromHomeKey*/, true /* awakenFromDreams */);
         } else {
             // This code brings home to the front or, if it is already
@@ -7842,8 +7903,11 @@
             // If the top fullscreen-or-dimming window is also the top fullscreen, respect
             // its light flag.
             vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-            vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
-                    & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+            if (!statusColorWin.isLetterboxedForDisplayCutoutLw()) {
+                // Only allow white status bar if the window was not letterboxed.
+                vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
+                        & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+            }
         } else if (statusColorWin != null && statusColorWin.isDimming()) {
             // Otherwise if it's dimming, clear the light flag.
             vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
@@ -7851,26 +7915,60 @@
         return vis;
     }
 
-    private int updateLightNavigationBarLw(int vis, WindowState opaque,
-            WindowState opaqueOrDimming) {
-        final WindowState imeWin = mWindowManagerFuncs.getInputMethodWindowLw();
+    @VisibleForTesting
+    @Nullable
+    static WindowState chooseNavigationColorWindowLw(WindowState opaque,
+            WindowState opaqueOrDimming, WindowState imeWindow,
+            @NavigationBarPosition int navBarPosition) {
+        // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
+        // window can be navigation color window.
+        final boolean imeWindowCanNavColorWindow = imeWindow != null
+                && imeWindow.isVisibleLw()
+                && navBarPosition == NAV_BAR_BOTTOM
+                && (PolicyControl.getWindowFlags(imeWindow, null)
+                & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
 
-        final WindowState navColorWin;
-        if (imeWin != null && imeWin.isVisibleLw() && mNavigationBarPosition == NAV_BAR_BOTTOM) {
-            navColorWin = imeWin;
-        } else {
-            navColorWin = opaqueOrDimming;
+        if (opaque != null && opaqueOrDimming == opaque) {
+            // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
+            // unless IME window is also eligible, since currently the IME window is always show
+            // above the opaque fullscreen app window, regardless of the IME target window.
+            // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
+            return imeWindowCanNavColorWindow ? imeWindow : opaque;
         }
 
+        if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
+            // No dimming window is involved. Determine the result only with the IME window.
+            return imeWindowCanNavColorWindow ? imeWindow : null;
+        }
+
+        if (!imeWindowCanNavColorWindow) {
+            // No IME window is involved. Determine the result only with opaqueOrDimming.
+            return opaqueOrDimming;
+        }
+
+        // The IME window and the dimming window are competing.  Check if the dimming window can be
+        // IME target or not.
+        if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
+            // The IME window is above the dimming window.
+            return imeWindow;
+        } else {
+            // The dimming window is above the IME window.
+            return opaqueOrDimming;
+        }
+    }
+
+    @VisibleForTesting
+    static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
+            WindowState imeWindow, WindowState navColorWin) {
+
         if (navColorWin != null) {
-            if (navColorWin == opaque) {
-                // If the top fullscreen-or-dimming window is also the top fullscreen, respect
-                // its light flag.
+            if (navColorWin == imeWindow || navColorWin == opaque) {
+                // Respect the light flag.
                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
                 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
                         & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-            } else if (navColorWin.isDimming() || navColorWin == imeWin) {
-                // Otherwise if it's dimming or it's the IME window, clear the light flag.
+            } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
+                // Clear the light flag for dimming window.
                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
             }
         }
@@ -8008,8 +8106,12 @@
 
         vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
 
+        final WindowState navColorWin = chooseNavigationColorWindowLw(
+                mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
+                mWindowManagerFuncs.getInputMethodWindowLw(), mNavigationBarPosition);
         vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
-                mTopFullscreenOpaqueOrDimmingWindowState);
+                mTopFullscreenOpaqueOrDimmingWindowState,
+                mWindowManagerFuncs.getInputMethodWindowLw(), navColorWin);
 
         return vis;
     }
@@ -8177,6 +8279,40 @@
     @Override
     public void writeToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
+        proto.write(LAST_SYSTEM_UI_FLAGS, mLastSystemUiFlags);
+        proto.write(ROTATION_MODE, mUserRotationMode);
+        proto.write(ROTATION, mUserRotation);
+        proto.write(ORIENTATION, mCurrentAppOrientation);
+        proto.write(SCREEN_ON_FULLY, mScreenOnFully);
+        proto.write(KEYGUARD_DRAW_COMPLETE, mKeyguardDrawComplete);
+        proto.write(WINDOW_MANAGER_DRAW_COMPLETE, mWindowManagerDrawComplete);
+        if (mFocusedApp != null) {
+            proto.write(FOCUSED_APP_TOKEN, mFocusedApp.toString());
+        }
+        if (mFocusedWindow != null) {
+            mFocusedWindow.writeIdentifierToProto(proto, FOCUSED_WINDOW);
+        }
+        if (mTopFullscreenOpaqueWindowState != null) {
+            mTopFullscreenOpaqueWindowState.writeIdentifierToProto(
+                    proto, TOP_FULLSCREEN_OPAQUE_WINDOW);
+        }
+        if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
+            mTopFullscreenOpaqueOrDimmingWindowState.writeIdentifierToProto(
+                    proto, TOP_FULLSCREEN_OPAQUE_OR_DIMMING_WINDOW);
+        }
+        proto.write(KEYGUARD_OCCLUDED, mKeyguardOccluded);
+        proto.write(KEYGUARD_OCCLUDED_CHANGED, mKeyguardOccludedChanged);
+        proto.write(KEYGUARD_OCCLUDED_PENDING, mPendingKeyguardOccluded);
+        proto.write(FORCE_STATUS_BAR, mForceStatusBar);
+        proto.write(FORCE_STATUS_BAR_FROM_KEYGUARD, mForceStatusBarFromKeyguard);
+        mStatusBarController.writeToProto(proto, STATUS_BAR);
+        mNavigationBarController.writeToProto(proto, NAVIGATION_BAR);
+        if (mOrientationListener != null) {
+            mOrientationListener.writeToProto(proto, ORIENTATION_LISTENER);
+        }
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.writeToProto(proto, KEYGUARD_DELEGATE);
+        }
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index cfe4088..60dae53 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -61,6 +61,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
@@ -136,10 +138,9 @@
  * </dl>
  */
 public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
-    // Navigation bar position values
-    int NAV_BAR_LEFT = 1 << 0;
-    int NAV_BAR_RIGHT = 1 << 1;
-    int NAV_BAR_BOTTOM = 1 << 2;
+    @Retention(SOURCE)
+    @IntDef({NAV_BAR_LEFT, NAV_BAR_RIGHT, NAV_BAR_BOTTOM})
+    @interface NavigationBarPosition {}
 
     /**
      * Pass this event to the user / app.  To be returned from
@@ -170,6 +171,11 @@
     void onKeyguardOccludedChangedLw(boolean occluded);
 
     /**
+     * Called when the resource overlays change.
+     */
+    default void onOverlayChangedLw() {}
+
+    /**
      * Interface to the Window Manager state associated with a particular
      * window.  You can hold on to an instance of this interface from the call
      * to prepareAddWindow() until removeWindow().
@@ -440,6 +446,13 @@
          */
         public boolean isDimming();
 
+        /**
+         * Returns true if the window is letterboxed for the display cutout.
+         */
+        default boolean isLetterboxedForDisplayCutoutLw() {
+            return false;
+        }
+
         /** @return the current windowing mode of this window. */
         int getWindowingMode();
 
@@ -468,6 +481,11 @@
          * visible. That is, they have the permission {@link Manifest.permission#DEVICE_POWER}.
          */
         boolean canAcquireSleepToken();
+
+        /**
+         * Writes {@link com.android.server.wm.proto.IdentifierProto} to stream.
+         */
+        void writeIdentifierToProto(ProtoOutputStream proto, long fieldId);
     }
 
     /**
@@ -1374,8 +1392,10 @@
      * Ask the policy to dismiss the keyguard, if it is currently shown.
      *
      * @param callback Callback to be informed about the result.
+     * @param message A message that should be displayed in the keyguard.
      */
-    public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback);
+    public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback,
+            CharSequence message);
 
     /**
      * Ask the policy whether the Keyguard has drawn. If the Keyguard is disabled, this method
@@ -1637,6 +1657,7 @@
      * @see #NAV_BAR_RIGHT
      * @see #NAV_BAR_BOTTOM
      */
+    @NavigationBarPosition
     int getNavBarPosition();
 
     /**
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index 169fd27..48a196d 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -16,6 +16,9 @@
 
 package com.android.server.policy;
 
+import static com.android.server.wm.proto.WindowOrientationListenerProto.ENABLED;
+import static com.android.server.wm.proto.WindowOrientationListenerProto.ROTATION;
+
 import android.content.Context;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
@@ -24,12 +27,11 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.text.TextUtils;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 import android.view.Surface;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -65,7 +67,7 @@
 
     /**
      * Creates a new WindowOrientationListener.
-     * 
+     *
      * @param context for the WindowOrientationListener.
      * @param handler Provides the Looper for receiving sensor updates.
      */
@@ -75,12 +77,12 @@
 
     /**
      * Creates a new WindowOrientationListener.
-     * 
+     *
      * @param context for the WindowOrientationListener.
      * @param handler Provides the Looper for receiving sensor updates.
      * @param rate at which sensor events are processed (see also
      * {@link android.hardware.SensorManager SensorManager}). Use the default
-     * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL 
+     * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL
      * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
      *
      * This constructor is private since no one uses it.
@@ -89,7 +91,28 @@
         mHandler = handler;
         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
         mRate = rate;
-        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DEVICE_ORIENTATION);
+        List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION);
+        Sensor wakeUpDeviceOrientationSensor = null;
+        Sensor nonWakeUpDeviceOrientationSensor = null;
+        /**
+         *  Prefer the wakeup form of the sensor if implemented.
+         *  It's OK to look for just two types of this sensor and use
+         *  the last found. Typical devices will only have one sensor of
+         *  this type.
+         */
+        for (Sensor s : l) {
+            if (s.isWakeUpSensor()) {
+                wakeUpDeviceOrientationSensor = s;
+            } else {
+                nonWakeUpDeviceOrientationSensor = s;
+            }
+        }
+
+        if (wakeUpDeviceOrientationSensor != null) {
+            mSensor = wakeUpDeviceOrientationSensor;
+        } else {
+            mSensor = nonWakeUpDeviceOrientationSensor;
+        }
 
         if (mSensor != null) {
             mOrientationJudge = new OrientationSensorJudge();
@@ -232,6 +255,15 @@
      */
     public abstract void onProposedRotationChanged(int rotation);
 
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        synchronized (mLock) {
+            proto.write(ENABLED, mEnabled);
+            proto.write(ROTATION, mCurrentRotation);
+        }
+        proto.end(token);
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         synchronized (mLock) {
             pw.println(prefix + TAG);
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 58002bc..18f4a3c 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,6 +1,11 @@
 package com.android.server.policy.keyguard;
 
 import static android.view.Display.INVALID_DISPLAY;
+import static com.android.server.wm.proto.KeyguardServiceDelegateProto.INTERACTIVE_STATE;
+import static com.android.server.wm.proto.KeyguardServiceDelegateProto.OCCLUDED;
+import static com.android.server.wm.proto.KeyguardServiceDelegateProto.SCREEN_STATE;
+import static com.android.server.wm.proto.KeyguardServiceDelegateProto.SECURE;
+import static com.android.server.wm.proto.KeyguardServiceDelegateProto.SHOWING;
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
@@ -15,6 +20,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 import android.view.WindowManagerPolicyConstants;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
@@ -257,9 +263,9 @@
         mKeyguardState.occluded = isOccluded;
     }
 
-    public void dismiss(IKeyguardDismissCallback callback) {
+    public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
         if (mKeyguardService != null) {
-            mKeyguardService.dismiss(callback);
+            mKeyguardService.dismiss(callback, message);
         }
     }
 
@@ -406,6 +412,16 @@
         }
     }
 
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(SHOWING, mKeyguardState.showing);
+        proto.write(OCCLUDED, mKeyguardState.occluded);
+        proto.write(SECURE, mKeyguardState.secure);
+        proto.write(SCREEN_STATE, mKeyguardState.screenState);
+        proto.write(INTERACTIVE_STATE, mKeyguardState.interactiveState);
+        proto.end(token);
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + TAG);
         prefix += "  ";
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 952e0b0..4e84868 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -74,9 +74,9 @@
     }
 
     @Override // Binder interface
-    public void dismiss(IKeyguardDismissCallback callback) {
+    public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
         try {
-            mService.dismiss(callback);
+            mService.dismiss(callback, message);
         } catch (RemoteException e) {
             Slog.w(TAG , "Remote Exception", e);
         }
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 6f005a3..a538967 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -20,6 +20,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.provider.Settings;
@@ -49,21 +50,6 @@
 
     public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
 
-    /** Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode. */
-    public static final int GPS_MODE_NO_CHANGE = 0;
-
-    /**
-     * Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
-     * is enabled and the screen is off.
-     */
-    public static final int GPS_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
-
-    /**
-     * Value of batterySaverGpsMode such that location should be disabled altogether
-     * when battery saver mode is enabled and the screen is off.
-     */
-    public static final int GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2;
-
     // Secure setting for GPS behavior when battery saver mode is on.
     public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode";
 
@@ -354,7 +340,7 @@
 
         // Get default value from Settings.Secure
         final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
-                GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
+                PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
         mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
 
         // Non-device-specific parameters.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 86b22bb..7273f62 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3140,7 +3140,8 @@
                     if (Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&
                             Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 &&
                             state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT &&
-                            state.mProcState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                            state.mProcState >
+                                    ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
                         disabled = true;
                     }
                 }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
index 0af19b6..bd8baeb 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
@@ -16,11 +16,11 @@
 package com.android.server.power.batterysaver;
 
 import android.content.Context;
+import android.os.PowerManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.util.Slog;
 
-import com.android.server.power.BatterySaverPolicy;
 import com.android.server.power.batterysaver.BatterySaverController.Plugin;
 
 public class BatterySaverLocationPlugin implements Plugin {
@@ -53,7 +53,7 @@
     private void updateLocationState(BatterySaverController caller) {
         final boolean kill =
                 (caller.getBatterySaverPolicy().getGpsMode()
-                        == BatterySaverPolicy.GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) &&
+                        == PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) &&
                 caller.isEnabled() && !caller.isInteractive();
 
         if (DEBUG) {
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index b31f4b3..2f5e2f8 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -555,7 +555,7 @@
             case StatsLog.CPU_TIME_PER_FREQ: {
                 List<StatsLogEventWrapper> ret = new ArrayList();
                 for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
-                    long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readDelta();
+                    long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
                     if (clusterTimeMs != null) {
                         for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
                             StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
@@ -743,9 +743,13 @@
                 filter.addAction(Intent.ACTION_SHUTDOWN);
                 mContext.registerReceiverAsUser(
                         mShutdownEventReceiver, UserHandle.ALL, filter, null, null);
-
-                // Pull the latest state of UID->app name, version mapping when statsd starts.
-                informAllUidsLocked(mContext);
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    // Pull the latest state of UID->app name, version mapping when statsd starts.
+                    informAllUidsLocked(mContext);
+                } finally {
+                    restoreCallingIdentity(token);
+                }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
                 forgetEverything();
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index ca0a450..28fee4e 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -42,6 +42,9 @@
 import android.service.trust.TrustAgentService;
 import android.util.Log;
 import android.util.Slog;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -67,6 +70,7 @@
     private static final int MSG_REMOVE_ESCROW_TOKEN = 8;
     private static final int MSG_ESCROW_TOKEN_STATE = 9;
     private static final int MSG_UNLOCK_USER = 10;
+    private static final int MSG_SHOW_KEYGUARD_ERROR_MESSAGE = 11;
 
     /**
      * Time in uptime millis that we wait for the service connection, both when starting
@@ -81,6 +85,7 @@
     private static final String DATA_ESCROW_TOKEN = "escrow_token";
     private static final String DATA_HANDLE = "handle";
     private static final String DATA_USER_ID = "user_id";
+    private static final String DATA_MESSAGE = "message";
 
     private final TrustManagerService mTrustManagerService;
     private final int mUserId;
@@ -255,6 +260,11 @@
                     mTrustManagerService.unlockUserWithToken(handle, eToken, userId);
                     break;
                 }
+                case MSG_SHOW_KEYGUARD_ERROR_MESSAGE: {
+                    CharSequence message = msg.getData().getCharSequence(DATA_MESSAGE);
+                    mTrustManagerService.showKeyguardErrorMessage(message);
+                    break;
+                }
             }
         }
     };
@@ -347,6 +357,14 @@
             msg.getData().putByteArray(DATA_ESCROW_TOKEN, token);
             msg.sendToTarget();
         }
+
+        @Override
+        public void showKeyguardErrorMessage(CharSequence message) {
+            if (DEBUG) Slog.d(TAG, "Showing keyguard error message: " + message);
+            Message msg = mHandler.obtainMessage(MSG_SHOW_KEYGUARD_ERROR_MESSAGE);
+            msg.getData().putCharSequence(DATA_MESSAGE, message);
+            msg.sendToTarget();
+        }
     };
 
     private final ServiceConnection mConnection = new ServiceConnection() {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index a7cd962..4413666 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -60,6 +60,7 @@
 import android.view.WindowManagerGlobal;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.SystemService;
@@ -249,6 +250,10 @@
         mLockPatternUtils.unlockUserWithToken(handle, token, userId);
     }
 
+    void showKeyguardErrorMessage(CharSequence message) {
+        dispatchOnTrustError(message);
+    }
+
     void refreshAgentList(int userIdOrAll) {
         if (DEBUG) Slog.d(TAG, "refreshAgentList(" + userIdOrAll + ")");
         if (!mTrustAgentsCanRun) {
@@ -769,6 +774,23 @@
         }
     }
 
+    private void dispatchOnTrustError(CharSequence message) {
+        if (DEBUG) {
+            Log.i(TAG, "onTrustError(" + message + ")");
+        }
+        for (int i = 0; i < mTrustListeners.size(); i++) {
+            try {
+                mTrustListeners.get(i).onTrustError(message);
+            } catch (DeadObjectException e) {
+                Slog.d(TAG, "Removing dead TrustListener.");
+                mTrustListeners.remove(i);
+                i--;
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception while notifying TrustListener.", e);
+            }
+        }
+    }
+
     // User lifecycle
 
     @Override
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index 487b52c..db95634 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -20,12 +20,16 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
+import static com.android.server.wm.proto.AppWindowThumbnailProto.HEIGHT;
+import static com.android.server.wm.proto.AppWindowThumbnailProto.SURFACE_ANIMATOR;
+import static com.android.server.wm.proto.AppWindowThumbnailProto.WIDTH;
 
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.os.Binder;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Builder;
@@ -114,6 +118,22 @@
         mSurfaceControl.destroy();
     }
 
+    /**
+     * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link
+     * com.android.server.wm.proto.AppWindowThumbnailProto}.
+     *
+     * @param proto Stream to write the AppWindowThumbnail object to.
+     * @param fieldId Field Id of the AppWindowThumbnail as defined in the parent message.
+     * @hide
+     */
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(WIDTH, mWidth);
+        proto.write(HEIGHT, mHeight);
+        mSurfaceAnimator.writeToProto(proto, SURFACE_ANIMATOR);
+        proto.end(token);
+    }
+
     @Override
     public Transaction getPendingTransaction() {
         return mAppToken.getPendingTransaction();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index fc0564d..a254ba2 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -24,6 +24,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.SurfaceControl.HIDDEN;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
@@ -51,7 +52,28 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
+import static com.android.server.wm.proto.AppWindowTokenProto.ALL_DRAWN;
+import static com.android.server.wm.proto.AppWindowTokenProto.APP_STOPPED;
+import static com.android.server.wm.proto.AppWindowTokenProto.CLIENT_HIDDEN;
+import static com.android.server.wm.proto.AppWindowTokenProto.DEFER_HIDING_CLIENT;
+import static com.android.server.wm.proto.AppWindowTokenProto.FILLS_PARENT;
+import static com.android.server.wm.proto.AppWindowTokenProto.FROZEN_BOUNDS;
+import static com.android.server.wm.proto.AppWindowTokenProto.HIDDEN_REQUESTED;
+import static com.android.server.wm.proto.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW;
+import static com.android.server.wm.proto.AppWindowTokenProto.IS_REALLY_ANIMATING;
+import static com.android.server.wm.proto.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START;
+import static com.android.server.wm.proto.AppWindowTokenProto.LAST_ALL_DRAWN;
+import static com.android.server.wm.proto.AppWindowTokenProto.LAST_SURFACE_SHOWING;
 import static com.android.server.wm.proto.AppWindowTokenProto.NAME;
+import static com.android.server.wm.proto.AppWindowTokenProto.NUM_DRAWN_WINDOWS;
+import static com.android.server.wm.proto.AppWindowTokenProto.NUM_INTERESTING_WINDOWS;
+import static com.android.server.wm.proto.AppWindowTokenProto.REMOVED;
+import static com.android.server.wm.proto.AppWindowTokenProto.REPORTED_DRAWN;
+import static com.android.server.wm.proto.AppWindowTokenProto.REPORTED_VISIBLE;
+import static com.android.server.wm.proto.AppWindowTokenProto.STARTING_DISPLAYED;
+import static com.android.server.wm.proto.AppWindowTokenProto.STARTING_MOVED;
+import static com.android.server.wm.proto.AppWindowTokenProto.STARTING_WINDOW;
+import static com.android.server.wm.proto.AppWindowTokenProto.THUMBNAIL;
 import static com.android.server.wm.proto.AppWindowTokenProto.WINDOW_TOKEN;
 
 import android.annotation.CallSuper;
@@ -224,6 +246,7 @@
 
     /** Whether this token should be boosted at the top of all app window tokens. */
     private boolean mNeedsZBoost;
+    private Letterbox mLetterbox;
 
     private final Point mTmpPoint = new Point();
     private final Rect mTmpRect = new Rect();
@@ -657,6 +680,7 @@
         if (destroyedSomething) {
             final DisplayContent dc = getDisplayContent();
             dc.assignWindowLayers(true /*setLayoutNeeded*/);
+            updateLetterbox(null);
         }
     }
 
@@ -923,6 +947,7 @@
     void removeChild(WindowState child) {
         super.removeChild(child);
         checkKeyguardFlagsChanged();
+        updateLetterbox(child);
     }
 
     private boolean waitingForReplacement() {
@@ -1388,6 +1413,33 @@
         return isInterestingAndDrawn;
     }
 
+    void updateLetterbox(WindowState winHint) {
+        final WindowState w = findMainWindow();
+        if (w != winHint && winHint != null && w != null) {
+            return;
+        }
+        final boolean needsLetterbox = w != null && w.isLetterboxedAppWindow()
+                && fillsParent() && w.hasDrawnLw();
+        if (needsLetterbox) {
+            if (mLetterbox == null) {
+                mLetterbox = new Letterbox(() -> makeChildSurface(null));
+            }
+            mLetterbox.setDimensions(mPendingTransaction, getParent().getBounds(), w.mFrame);
+        } else if (mLetterbox != null) {
+            final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+            // Make sure we have a transaction here, in case we're called outside of a transaction.
+            // This does not use mPendingTransaction, because SurfaceAnimator uses a
+            // global transaction in onAnimationEnd.
+            SurfaceControl.openTransaction();
+            try {
+                mLetterbox.hide(t);
+            } finally {
+                SurfaceControl.mergeToGlobalTransaction(t);
+                SurfaceControl.closeTransaction();
+            }
+        }
+    }
+
     @Override
     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
         // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent
@@ -1614,6 +1666,8 @@
             // the status bar). In that case we need to use the final frame.
             if (freeform) {
                 frame.set(win.mFrame);
+            } else if (win.isLetterboxedAppWindow()) {
+                frame.set(getTask().getBounds());
             } else {
                 frame.set(win.mContainingFrame);
             }
@@ -1936,6 +1990,34 @@
         final long token = proto.start(fieldId);
         writeNameToProto(proto, NAME);
         super.writeToProto(proto, WINDOW_TOKEN, trim);
+        proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
+        proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
+        proto.write(IS_REALLY_ANIMATING, isReallyAnimating());
+        if (mThumbnail != null){
+            mThumbnail.writeToProto(proto, THUMBNAIL);
+        }
+        proto.write(FILLS_PARENT, mFillsParent);
+        proto.write(APP_STOPPED, mAppStopped);
+        proto.write(HIDDEN_REQUESTED, hiddenRequested);
+        proto.write(CLIENT_HIDDEN, mClientHidden);
+        proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
+        proto.write(REPORTED_DRAWN, reportedDrawn);
+        proto.write(REPORTED_VISIBLE, reportedVisible);
+        proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows);
+        proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows);
+        proto.write(ALL_DRAWN, allDrawn);
+        proto.write(LAST_ALL_DRAWN, mLastAllDrawn);
+        proto.write(REMOVED, removed);
+        if (startingWindow != null){
+            startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
+        }
+        proto.write(STARTING_DISPLAYED, startingDisplayed);
+        proto.write(STARTING_MOVED, startingMoved);
+        proto.write(HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW,
+                mHiddenSetFromTransferredStartingWindow);
+        for (Rect bounds : mFrozenBounds) {
+            bounds.writeToProto(proto, FROZEN_BOUNDS);
+        }
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2cc2a0e..a8e00dd 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -62,6 +62,7 @@
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
@@ -121,6 +122,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
+import android.graphics.Path;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
@@ -137,6 +139,7 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
+import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.InputDevice;
 import android.view.MagnificationSpec;
@@ -158,6 +161,7 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
@@ -208,6 +212,9 @@
     int mInitialDisplayHeight = 0;
     int mInitialDisplayDensity = 0;
 
+    DisplayCutout mInitialDisplayCutout;
+    DisplayCutout mDisplayCutoutOverride;
+
     /**
      * Overridden display size. Initialized with {@link #mInitialDisplayWidth}
      * and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
@@ -690,6 +697,7 @@
 
         final AppWindowToken atoken = w.mAppToken;
         if (atoken != null) {
+            atoken.updateLetterbox(w);
             final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w);
             if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) {
                 mTmpUpdateAllDrawn.add(atoken);
@@ -1160,6 +1168,7 @@
             mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics,
                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
         }
+        mDisplayInfo.displayCutout = calculateDisplayCutoutForCurrentRotation();
         mDisplayInfo.getAppMetrics(mDisplayMetrics);
         if (mDisplayScalingDisabled) {
             mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
@@ -1181,6 +1190,18 @@
         return mDisplayInfo;
     }
 
+    DisplayCutout calculateDisplayCutoutForCurrentRotation() {
+        final DisplayCutout cutout = mInitialDisplayCutout;
+        if (cutout == null || cutout == DisplayCutout.NO_CUTOUT || mRotation == ROTATION_0) {
+            return cutout;
+        }
+        final Path bounds = cutout.getBounds().getBoundaryPath();
+        transformPhysicalToLogicalCoordinates(mRotation, mInitialDisplayWidth,
+                mInitialDisplayHeight, mTmpMatrix);
+        bounds.transform(mTmpMatrix);
+        return DisplayCutout.fromBounds(bounds);
+    }
+
     /**
      * Compute display configuration based on display properties and policy settings.
      * Do not call if mDisplayReady == false.
@@ -1643,6 +1664,7 @@
         mInitialDisplayWidth = mDisplayInfo.logicalWidth;
         mInitialDisplayHeight = mDisplayInfo.logicalHeight;
         mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
+        mInitialDisplayCutout = mDisplayInfo.displayCutout;
     }
 
     /**
@@ -1657,10 +1679,12 @@
         final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
         final int newHeight = rotated ? mDisplayInfo.logicalWidth : mDisplayInfo.logicalHeight;
         final int newDensity = mDisplayInfo.logicalDensityDpi;
+        final DisplayCutout newCutout = mDisplayInfo.displayCutout;
 
         final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
                 || mInitialDisplayHeight != newHeight
-                || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi;
+                || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi
+                || !Objects.equals(mInitialDisplayCutout, newCutout);
 
         if (displayMetricsChanged) {
             // Check if display size or density is forced.
@@ -1677,6 +1701,7 @@
             mInitialDisplayWidth = newWidth;
             mInitialDisplayHeight = newHeight;
             mInitialDisplayDensity = newDensity;
+            mInitialDisplayCutout = newCutout;
             mService.reconfigureDisplayLocked(this);
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 0155712..13d0c86 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -22,6 +22,7 @@
 import static com.android.server.wm.proto.DisplayFramesProto.STABLE_BOUNDS;
 
 import android.annotation.NonNull;
+import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
@@ -100,9 +101,12 @@
     /** During layout, the current screen borders along which input method windows are placed. */
     public final Rect mDock = new Rect();
 
-    /** Definition of the cutout */
+    /** The display cutout used for layout (after rotation) */
     @NonNull public DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
 
+    /** The cutout as supplied by display info */
+    @NonNull private DisplayCutout mDisplayInfoCutout = DisplayCutout.NO_CUTOUT;
+
     /**
      * During layout, the frame that is display-cutout safe, i.e. that does not intersect with it.
      */
@@ -126,9 +130,11 @@
         mRotation = info.rotation;
         mDisplayInfoOverscan.set(
                 info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
+        mDisplayInfoCutout = info.displayCutout != null
+                ? info.displayCutout : DisplayCutout.NO_CUTOUT;
     }
 
-    public void onBeginLayout(boolean emulateDisplayCutout, int statusBarHeight) {
+    public void onBeginLayout() {
         switch (mRotation) {
             case ROTATION_90:
                 mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.top;
@@ -166,11 +172,24 @@
         mStable.set(mUnrestricted);
         mStableFullscreen.set(mUnrestricted);
         mCurrent.set(mUnrestricted);
-        mDisplayCutout = DisplayCutout.NO_CUTOUT;
+
+        mDisplayCutout = mDisplayInfoCutout.calculateRelativeTo(mOverscan);
         mDisplayCutoutSafe.set(Integer.MIN_VALUE, Integer.MIN_VALUE,
                 Integer.MAX_VALUE, Integer.MAX_VALUE);
-        if (emulateDisplayCutout) {
-            setEmulatedDisplayCutout((int) (statusBarHeight * 0.8));
+        if (!mDisplayCutout.isEmpty()) {
+            final DisplayCutout c = mDisplayCutout;
+            if (c.getSafeInsetLeft() > 0) {
+                mDisplayCutoutSafe.left = mRestrictedOverscan.left + c.getSafeInsetLeft();
+            }
+            if (c.getSafeInsetTop() > 0) {
+                mDisplayCutoutSafe.top = mRestrictedOverscan.top + c.getSafeInsetTop();
+            }
+            if (c.getSafeInsetRight() > 0) {
+                mDisplayCutoutSafe.right = mRestrictedOverscan.right - c.getSafeInsetRight();
+            }
+            if (c.getSafeInsetBottom() > 0) {
+                mDisplayCutoutSafe.bottom = mRestrictedOverscan.bottom - c.getSafeInsetBottom();
+            }
         }
     }
 
@@ -178,55 +197,6 @@
         return mDock.bottom - mCurrent.bottom;
     }
 
-    private void setEmulatedDisplayCutout(int height) {
-        final boolean swappedDimensions = mRotation == ROTATION_90 || mRotation == ROTATION_270;
-
-        final int screenWidth = swappedDimensions ? mDisplayHeight : mDisplayWidth;
-        final int screenHeight = swappedDimensions ? mDisplayWidth : mDisplayHeight;
-
-        final int widthTop = (int) (screenWidth * 0.3);
-        final int widthBottom = widthTop - height;
-
-        switch (mRotation) {
-            case ROTATION_90:
-                mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
-                        new Point(0, (screenWidth - widthTop) / 2),
-                        new Point(height, (screenWidth - widthBottom) / 2),
-                        new Point(height, (screenWidth + widthBottom) / 2),
-                        new Point(0, (screenWidth + widthTop) / 2)
-                )).calculateRelativeTo(mUnrestricted);
-                mDisplayCutoutSafe.left = height;
-                break;
-            case ROTATION_180:
-                mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
-                        new Point((screenWidth - widthTop) / 2, screenHeight),
-                        new Point((screenWidth - widthBottom) / 2, screenHeight - height),
-                        new Point((screenWidth + widthBottom) / 2, screenHeight - height),
-                        new Point((screenWidth + widthTop) / 2, screenHeight)
-                )).calculateRelativeTo(mUnrestricted);
-                mDisplayCutoutSafe.bottom = screenHeight - height;
-                break;
-            case ROTATION_270:
-                mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
-                        new Point(screenHeight, (screenWidth - widthTop) / 2),
-                        new Point(screenHeight - height, (screenWidth - widthBottom) / 2),
-                        new Point(screenHeight - height, (screenWidth + widthBottom) / 2),
-                        new Point(screenHeight, (screenWidth + widthTop) / 2)
-                )).calculateRelativeTo(mUnrestricted);
-                mDisplayCutoutSafe.right = screenHeight - height;
-                break;
-            default:
-                mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
-                        new Point((screenWidth - widthTop) / 2, 0),
-                        new Point((screenWidth - widthBottom) / 2, height),
-                        new Point((screenWidth + widthBottom) / 2, height),
-                        new Point((screenWidth + widthTop) / 2, 0)
-                )).calculateRelativeTo(mUnrestricted);
-                mDisplayCutoutSafe.top = height;
-                break;
-        }
-    }
-
     public void writeToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         mStable.writeToProto(proto, STABLE_BOUNDS);
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 28b4c1d..0171b56 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -136,7 +136,7 @@
             outSurface.copyFrom(surface);
             final IBinder winBinder = window.asBinder();
             IBinder token = new Binder();
-            mDragState = new DragState(mService, token, surface, flags, winBinder);
+            mDragState = new DragState(mService, this, token, surface, flags, winBinder);
             mDragState.mPid = callerPid;
             mDragState.mUid = callerUid;
             mDragState.mOriginalAlpha = alpha;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index b9f437a..1ac9b88 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -42,6 +42,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.IUserManager;
+import android.os.UserManagerInternal;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DragEvent;
@@ -55,6 +56,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.view.IDragAndDropPermissions;
+import com.android.server.LocalServices;
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
 
@@ -116,10 +118,10 @@
     private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
     private Point mDisplaySize = new Point();
 
-    DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
-            int flags, IBinder localWin) {
+    DragState(WindowManagerService service, DragDropController controller, IBinder token,
+            SurfaceControl surface, int flags, IBinder localWin) {
         mService = service;
-        mDragDropController = service.mDragDropController;
+        mDragDropController = controller;
         mToken = token;
         mSurfaceControl = surface;
         mFlags = flags;
@@ -318,15 +320,9 @@
 
         mSourceUserId = UserHandle.getUserId(mUid);
 
-        final IUserManager userManager =
-                (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
-        try {
-            mCrossProfileCopyAllowed = !userManager.getUserRestrictions(mSourceUserId).getBoolean(
-                    UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
-        } catch (RemoteException e) {
-            Slog.e(TAG_WM, "Remote Exception calling UserManager: " + e);
-            mCrossProfileCopyAllowed = false;
-        }
+        final UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
+        mCrossProfileCopyAllowed = !userManager.getUserRestriction(
+                mSourceUserId, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
 
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
@@ -534,7 +530,8 @@
         final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
 
         final DragAndDropPermissionsHandler dragAndDropPermissions;
-        if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
+        if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
+                && mData != null) {
             dragAndDropPermissions = new DragAndDropPermissionsHandler(
                     mData,
                     mUid,
@@ -546,7 +543,9 @@
             dragAndDropPermissions = null;
         }
         if (mSourceUserId != targetUserId){
-            mData.fixUris(mSourceUserId);
+            if (mData != null) {
+                mData.fixUris(mSourceUserId);
+            }
         }
         final int myPid = Process.myPid();
         final IBinder token = touchedWin.mClient.asBinder();
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
new file mode 100644
index 0000000..8fa79ab
--- /dev/null
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.SurfaceControl.HIDDEN;
+
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import java.util.function.Supplier;
+
+/**
+ * Manages a set of {@link SurfaceControl}s to draw a black letterbox between an
+ * outer rect and an inner rect.
+ */
+public class Letterbox {
+
+    private static final Rect EMPTY_RECT = new Rect();
+
+    private final Supplier<SurfaceControl.Builder> mFactory;
+    private final Rect mOuter = new Rect();
+    private final Rect mInner = new Rect();
+    private final LetterboxSurface mTop = new LetterboxSurface("top");
+    private final LetterboxSurface mLeft = new LetterboxSurface("left");
+    private final LetterboxSurface mBottom = new LetterboxSurface("bottom");
+    private final LetterboxSurface mRight = new LetterboxSurface("right");
+
+    /**
+     * Constructs a Letterbox.
+     *
+     * @param surfaceControlFactory a factory for creating the managed {@link SurfaceControl}s
+     */
+    public Letterbox(Supplier<SurfaceControl.Builder> surfaceControlFactory) {
+        mFactory = surfaceControlFactory;
+    }
+
+    /**
+     * Sets the dimensions of the the letterbox, such that the area between the outer and inner
+     * frames will be covered by black color surfaces.
+     *
+     * @param t     a transaction in which to set the dimensions
+     * @param outer the outer frame of the letterbox (this frame will be black, except the area
+     *              that intersects with the {code inner} frame).
+     * @param inner the inner frame of the letterbox (this frame will be clear)
+     */
+    public void setDimensions(SurfaceControl.Transaction t, Rect outer, Rect inner) {
+        mOuter.set(outer);
+        mInner.set(inner);
+
+        mTop.setRect(t, outer.left, outer.top, inner.right, inner.top);
+        mLeft.setRect(t, outer.left, inner.top, inner.left, outer.bottom);
+        mBottom.setRect(t, inner.left, inner.bottom, outer.right, outer.bottom);
+        mRight.setRect(t, inner.right, outer.top, outer.right, inner.bottom);
+    }
+
+    /**
+     * Hides the letterbox.
+     *
+     * @param t a transaction in which to hide the letterbox
+     */
+    public void hide(SurfaceControl.Transaction t) {
+        setDimensions(t, EMPTY_RECT, EMPTY_RECT);
+    }
+
+    /**
+     * Destroys the managed {@link SurfaceControl}s.
+     */
+    public void destroy() {
+        mOuter.setEmpty();
+        mInner.setEmpty();
+
+        mTop.destroy();
+        mLeft.destroy();
+        mBottom.destroy();
+        mRight.destroy();
+    }
+
+    private class LetterboxSurface {
+
+        private final String mType;
+        private SurfaceControl mSurface;
+
+        private int mLastLeft = 0;
+        private int mLastTop = 0;
+        private int mLastRight = 0;
+        private int mLastBottom = 0;
+
+        public LetterboxSurface(String type) {
+            mType = type;
+        }
+
+        public void setRect(SurfaceControl.Transaction t,
+                int left, int top, int right, int bottom) {
+            if (mLastLeft == left && mLastTop == top
+                    && mLastRight == right && mLastBottom == bottom) {
+                // Nothing changed.
+                return;
+            }
+
+            if (left < right && top < bottom) {
+                if (mSurface == null) {
+                    createSurface();
+                }
+                t.setPosition(mSurface, left, top);
+                t.setSize(mSurface, right - left, bottom - top);
+                t.show(mSurface);
+            } else if (mSurface != null) {
+                t.hide(mSurface);
+            }
+
+            mLastLeft = left;
+            mLastTop = top;
+            mLastRight = right;
+            mLastBottom = bottom;
+        }
+
+        private void createSurface() {
+            mSurface = mFactory.get().setName("Letterbox - " + mType)
+                    .setFlags(HIDDEN).setColorLayer(true).build();
+            mSurface.setLayer(-1);
+            mSurface.setColor(new float[]{0, 0, 0});
+        }
+
+        public void destroy() {
+            if (mSurface != null) {
+                mSurface.destroy();
+                mSurface = null;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 69cbe46..62519e1 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -360,14 +360,19 @@
      * Sets the Ime state and height.
      */
     void setAdjustedForIme(boolean adjustedForIme, int imeHeight) {
-        // Return early if there is no state change
-        if (mIsImeShowing == adjustedForIme && mImeHeight == imeHeight) {
+        // Due to the order of callbacks from the system, we may receive an ime height even when
+        // {@param adjustedForIme} is false, and also a zero height when {@param adjustedForIme}
+        // is true.  Instead, ensure that the ime state changes with the height and if the ime is
+        // showing, then the height is non-zero.
+        final boolean imeShowing = adjustedForIme && imeHeight > 0;
+        imeHeight = imeShowing ? imeHeight : 0;
+        if (imeShowing == mIsImeShowing && imeHeight == mImeHeight) {
             return;
         }
 
-        mIsImeShowing = adjustedForIme;
+        mIsImeShowing = imeShowing;
         mImeHeight = imeHeight;
-        notifyImeVisibilityChanged(adjustedForIme, imeHeight);
+        notifyImeVisibilityChanged(imeShowing, imeHeight);
         notifyMovementBoundsChanged(true /* fromImeAdjustment */);
     }
 
diff --git a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
index d2cbf88..33e560f 100644
--- a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
+++ b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
@@ -33,7 +33,7 @@
 // the surface control.
 //
 // See cts/hostsidetests/../../SurfaceTraceReceiver.java for parsing side.
-class RemoteSurfaceTrace extends SurfaceControlWithBackground {
+class RemoteSurfaceTrace extends SurfaceControl {
     static final String TAG = "RemoteSurfaceTrace";
 
     final FileDescriptor mWriteFd;
@@ -42,7 +42,7 @@
     final WindowManagerService mService;
     final WindowState mWindow;
 
-    RemoteSurfaceTrace(FileDescriptor fd, SurfaceControlWithBackground wrapped,
+    RemoteSurfaceTrace(FileDescriptor fd, SurfaceControl wrapped,
             WindowState window) {
         super(wrapped);
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2a77c92..2cc96c9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -86,7 +86,6 @@
 import static com.android.server.wm.WindowManagerService.logSurface;
 import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
-import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
@@ -968,9 +967,7 @@
                 doRequest = true;
             }
         }
-        if ((bulkUpdateParams & SET_TURN_ON_SCREEN) != 0) {
-            mService.mTurnOnScreen = true;
-        }
+
         if ((bulkUpdateParams & SET_WALLPAPER_ACTION_PENDING) != 0) {
             mWallpaperActionPending = true;
         }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index e67cdba..10f1c3a 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -19,11 +19,14 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.proto.SurfaceAnimatorProto.ANIMATION_ADAPTER;
+import static com.android.server.wm.proto.SurfaceAnimatorProto.ANIMATION_START_DELAYED;
+import static com.android.server.wm.proto.SurfaceAnimatorProto.LEASH;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 
@@ -309,6 +312,24 @@
         return leash;
     }
 
+    /**
+     * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link
+     * com.android.server.wm.proto.SurfaceAnimatorProto}.
+     *
+     * @param proto Stream to write the SurfaceAnimator object to.
+     * @param fieldId Field Id of the SurfaceAnimator as defined in the parent message.
+     * @hide
+     */
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(ANIMATION_ADAPTER, mAnimation != null ? mAnimation.toString() : "null");
+        if (mLeash != null){
+            mLeash.writeToProto(proto, LEASH);
+        }
+        proto.write(ANIMATION_START_DELAYED, mAnimationStartDelayed);
+        proto.end(token);
+    }
+
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mAnimation="); pw.print(mAnimation);
         pw.print(" mLeash="); pw.println(mLeash);
diff --git a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
deleted file mode 100644
index 7c5bd43..0000000
--- a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
-
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.view.Surface;
-import android.view.Surface.OutOfResourcesException;
-import android.view.SurfaceControl;
-
-/**
- * SurfaceControl extension that has black background behind navigation bar area for fullscreen
- * letterboxed apps.
- */
-class SurfaceControlWithBackground extends SurfaceControl {
-    // SurfaceControl that holds the background.
-    private SurfaceControl mBackgroundControl;
-
-    // Flag that defines whether the background should be shown.
-    private boolean mVisible;
-
-    // Way to communicate with corresponding window.
-    private WindowSurfaceController mWindowSurfaceController;
-
-    // Rect to hold task bounds when computing metrics for background.
-    private Rect mTmpContainerRect = new Rect();
-
-    // Last metrics applied to the main SurfaceControl.
-    private float mLastWidth, mLastHeight;
-    private float mLastDsDx = 1, mLastDsDy = 1;
-    private float mLastX, mLastY;
-
-    // SurfaceFlinger doesn't support crop rectangles where width or height is non-positive.
-    // If we just set an empty crop it will behave as if there is no crop at all.
-    // To fix this we explicitly hide the surface and won't let it to be shown.
-    private boolean mHiddenForCrop = false;
-
-    public SurfaceControlWithBackground(SurfaceControlWithBackground other) {
-        super(other);
-        mBackgroundControl = other.mBackgroundControl;
-        mVisible = other.mVisible;
-        mWindowSurfaceController = other.mWindowSurfaceController;
-    }
-
-    public SurfaceControlWithBackground(String name, SurfaceControl.Builder b,
-            int windowType, int w, int h,
-            WindowSurfaceController windowSurfaceController) throws OutOfResourcesException {
-        super(b.build());
-
-        // We should only show background behind app windows that are letterboxed in a task.
-        if ((windowType != TYPE_BASE_APPLICATION && windowType != TYPE_APPLICATION_STARTING)
-                || !windowSurfaceController.mAnimator.mWin.isLetterboxedAppWindow()) {
-            return;
-        }
-        mWindowSurfaceController = windowSurfaceController;
-        mLastWidth = w;
-        mLastHeight = h;
-        mWindowSurfaceController.getContainerRect(mTmpContainerRect);
-        mBackgroundControl = b.setName("Background for - " + name)
-                .setSize(mTmpContainerRect.width(), mTmpContainerRect.height())
-                .setFormat(OPAQUE)
-                .setColorLayer(true)
-                .build();
-    }
-
-    @Override
-    public void setAlpha(float alpha) {
-        super.setAlpha(alpha);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mBackgroundControl.setAlpha(alpha);
-    }
-
-    @Override
-    public void setLayer(int zorder) {
-        super.setLayer(zorder);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        // TODO: Use setRelativeLayer(Integer.MIN_VALUE) when it's fixed.
-        mBackgroundControl.setLayer(zorder - 1);
-    }
-
-    @Override
-    public void setPosition(float x, float y) {
-        super.setPosition(x, y);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mLastX = x;
-        mLastY = y;
-        updateBgPosition();
-    }
-
-    private void updateBgPosition() {
-        mWindowSurfaceController.getContainerRect(mTmpContainerRect);
-        final Rect winFrame = mWindowSurfaceController.mAnimator.mWin.mFrame;
-        final float offsetX = (mTmpContainerRect.left - winFrame.left) * mLastDsDx;
-        final float offsetY = (mTmpContainerRect.top - winFrame.top) * mLastDsDy;
-        mBackgroundControl.setPosition(mLastX + offsetX, mLastY + offsetY);
-    }
-
-    @Override
-    public void setSize(int w, int h) {
-        super.setSize(w, h);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mLastWidth = w;
-        mLastHeight = h;
-        mWindowSurfaceController.getContainerRect(mTmpContainerRect);
-        mBackgroundControl.setSize(mTmpContainerRect.width(), mTmpContainerRect.height());
-    }
-
-    @Override
-    public void setWindowCrop(Rect crop) {
-        super.setWindowCrop(crop);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        calculateBgCrop(crop);
-        mBackgroundControl.setWindowCrop(mTmpContainerRect);
-        mHiddenForCrop = mTmpContainerRect.isEmpty();
-        updateBackgroundVisibility();
-    }
-
-    @Override
-    public void setFinalCrop(Rect crop) {
-        super.setFinalCrop(crop);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mWindowSurfaceController.getContainerRect(mTmpContainerRect);
-        mBackgroundControl.setFinalCrop(mTmpContainerRect);
-    }
-
-    /**
-     * Compute background crop based on current animation progress for main surface control and
-     * update {@link #mTmpContainerRect} with new values.
-     */
-    private void calculateBgCrop(Rect crop) {
-        // Track overall progress of animation by computing cropped portion of status bar.
-        final Rect contentInsets = mWindowSurfaceController.mAnimator.mWin.mContentInsets;
-        float d = contentInsets.top == 0 ? 0 : (float) crop.top / contentInsets.top;
-        if (d > 1.f) {
-            // We're running expand animation from launcher, won't compute custom bg crop here.
-            mTmpContainerRect.setEmpty();
-            return;
-        }
-
-        // Compute new scaled width and height for background that will depend on current animation
-        // progress. Those consist of current crop rect for the main surface + scaled areas outside
-        // of letterboxed area.
-        // TODO: Because the progress is computed with low precision we're getting smaller values
-        // for background width/height then screen size at the end of the animation. Will round when
-        // the value is smaller then some empiric epsilon. However, this should be fixed by
-        // computing correct frames for letterboxed windows in WindowState.
-        d = d < 0.025f ? 0 : d;
-        mWindowSurfaceController.getContainerRect(mTmpContainerRect);
-        int backgroundWidth = 0, backgroundHeight = 0;
-        // Compute additional offset for the background when app window is positioned not at (0,0).
-        // E.g. landscape with navigation bar on the left.
-        final Rect winFrame = mWindowSurfaceController.mAnimator.mWin.mFrame;
-        int offsetX = (int)((winFrame.left - mTmpContainerRect.left) * mLastDsDx),
-                offsetY = (int) ((winFrame.top - mTmpContainerRect.top) * mLastDsDy);
-
-        // Position and size background.
-        final int bgPosition = mWindowSurfaceController.mAnimator.mService.getNavBarPosition();
-
-        switch (bgPosition) {
-            case NAV_BAR_LEFT:
-                backgroundWidth = (int) ((mTmpContainerRect.width() - mLastWidth) * (1 - d) + 0.5);
-                backgroundHeight = crop.height();
-                offsetX += crop.left - backgroundWidth;
-                offsetY += crop.top;
-                break;
-            case NAV_BAR_RIGHT:
-                backgroundWidth = (int) ((mTmpContainerRect.width() - mLastWidth) * (1 - d) + 0.5);
-                backgroundHeight = crop.height();
-                offsetX += crop.right;
-                offsetY += crop.top;
-                break;
-            case NAV_BAR_BOTTOM:
-                backgroundWidth = crop.width();
-                backgroundHeight = (int) ((mTmpContainerRect.height() - mLastHeight) * (1 - d)
-                        + 0.5);
-                offsetX += crop.left;
-                offsetY += crop.bottom;
-                break;
-        }
-        mTmpContainerRect.set(offsetX, offsetY, offsetX + backgroundWidth,
-                offsetY + backgroundHeight);
-    }
-
-    @Override
-    public void setLayerStack(int layerStack) {
-        super.setLayerStack(layerStack);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mBackgroundControl.setLayerStack(layerStack);
-    }
-
-    @Override
-    public void setOpaque(boolean isOpaque) {
-        super.setOpaque(isOpaque);
-        updateBackgroundVisibility();
-    }
-
-    @Override
-    public void setSecure(boolean isSecure) {
-        super.setSecure(isSecure);
-    }
-
-    @Override
-    public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
-        super.setMatrix(dsdx, dtdx, dtdy, dsdy);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mBackgroundControl.setMatrix(dsdx, dtdx, dtdy, dsdy);
-        mLastDsDx = dsdx;
-        mLastDsDy = dsdy;
-        updateBgPosition();
-    }
-
-    @Override
-    public void hide() {
-        super.hide();
-        mVisible = false;
-        updateBackgroundVisibility();
-    }
-
-    @Override
-    public void show() {
-        super.show();
-        mVisible = true;
-        updateBackgroundVisibility();
-    }
-
-    @Override
-    public void destroy() {
-        super.destroy();
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mBackgroundControl.destroy();
-    }
-
-    @Override
-    public void release() {
-        super.release();
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mBackgroundControl.release();
-    }
-
-    @Override
-    public void setTransparentRegionHint(Region region) {
-        super.setTransparentRegionHint(region);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mBackgroundControl.setTransparentRegionHint(region);
-    }
-
-    @Override
-    public void deferTransactionUntil(IBinder handle, long frame) {
-        super.deferTransactionUntil(handle, frame);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mBackgroundControl.deferTransactionUntil(handle, frame);
-    }
-
-    @Override
-    public void deferTransactionUntil(Surface barrier, long frame) {
-        super.deferTransactionUntil(barrier, frame);
-
-        if (mBackgroundControl == null) {
-            return;
-        }
-        mBackgroundControl.deferTransactionUntil(barrier, frame);
-    }
-
-    private void updateBackgroundVisibility() {
-        if (mBackgroundControl == null) {
-            return;
-        }
-        final AppWindowToken appWindowToken = mWindowSurfaceController.mAnimator.mWin.mAppToken;
-        if (!mHiddenForCrop && mVisible && appWindowToken != null && appWindowToken.fillsParent()) {
-            mBackgroundControl.show();
-        } else {
-            mBackgroundControl.hide();
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3c96ca1..0628436 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -22,13 +22,13 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.res.Configuration.EMPTY;
-
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.proto.TaskProto.APP_WINDOW_TOKENS;
 import static com.android.server.wm.proto.TaskProto.BOUNDS;
+import static com.android.server.wm.proto.TaskProto.DEFER_REMOVAL;
 import static com.android.server.wm.proto.TaskProto.FILLS_PARENT;
 import static com.android.server.wm.proto.TaskProto.ID;
 import static com.android.server.wm.proto.TaskProto.TEMP_INSET_BOUNDS;
@@ -670,6 +670,7 @@
         proto.write(FILLS_PARENT, matchParentBounds());
         getBounds().writeToProto(proto, BOUNDS);
         mTempInsetBounds.writeToProto(proto, TEMP_INSET_BOUNDS);
+        proto.write(DEFER_REMOVAL, mDeferRemoval);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7b4281c..8a36226 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -16,8 +16,8 @@
 
 package com.android.server.wm;
 
-import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -31,14 +31,19 @@
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
-
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.proto.StackProto.ADJUSTED_BOUNDS;
+import static com.android.server.wm.proto.StackProto.ADJUSTED_FOR_IME;
+import static com.android.server.wm.proto.StackProto.ADJUST_DIVIDER_AMOUNT;
+import static com.android.server.wm.proto.StackProto.ADJUST_IME_AMOUNT;
 import static com.android.server.wm.proto.StackProto.ANIMATION_BACKGROUND_SURFACE_IS_DIMMING;
 import static com.android.server.wm.proto.StackProto.BOUNDS;
+import static com.android.server.wm.proto.StackProto.DEFER_REMOVAL;
 import static com.android.server.wm.proto.StackProto.FILLS_PARENT;
 import static com.android.server.wm.proto.StackProto.ID;
+import static com.android.server.wm.proto.StackProto.MINIMIZE_AMOUNT;
 import static com.android.server.wm.proto.StackProto.TASKS;
 import static com.android.server.wm.proto.StackProto.WINDOW_CONTAINER;
 
@@ -1316,6 +1321,12 @@
         proto.write(FILLS_PARENT, matchParentBounds());
         getRawBounds().writeToProto(proto, BOUNDS);
         proto.write(ANIMATION_BACKGROUND_SURFACE_IS_DIMMING, mAnimationBackgroundSurfaceIsShown);
+        proto.write(DEFER_REMOVAL, mDeferRemoval);
+        proto.write(MINIMIZE_AMOUNT, mMinimizeAmount);
+        proto.write(ADJUSTED_FOR_IME, mAdjustedForIme);
+        proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount);
+        proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount);
+        mAdjustedBounds.writeToProto(proto, ADJUSTED_BOUNDS);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 3efd6ac..cec13ab 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -292,9 +292,6 @@
         if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
             builder.append(" ORIENTATION_CHANGE_COMPLETE");
         }
-        if ((bulkUpdateParams & WindowSurfacePlacer.SET_TURN_ON_SCREEN) != 0) {
-            builder.append(" TURN_ON_SCREEN");
-        }
         return builder.toString();
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 36e6418..42c6ec2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -19,26 +19,26 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.SurfaceControl.Transaction;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
 import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
+import static com.android.server.wm.proto.WindowContainerProto.SURFACE_ANIMATOR;
 import static com.android.server.wm.proto.WindowContainerProto.VISIBLE;
-import static android.view.SurfaceControl.Transaction;
 
 import android.annotation.CallSuper;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.util.Pools;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 import android.view.MagnificationSpec;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Builder;
 import android.view.SurfaceSession;
-import android.util.Pools;
-
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.wm.SurfaceAnimator.Animatable;
@@ -972,6 +972,7 @@
         super.writeToProto(proto, CONFIGURATION_CONTAINER, trim);
         proto.write(ORIENTATION, mOrientation);
         proto.write(VISIBLE, isVisible());
+        mSurfaceAnimator.writeToProto(proto, SURFACE_ANIMATOR);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e91b16d..d2ab9df 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2941,10 +2941,10 @@
     }
 
     @Override
-    public void dismissKeyguard(IKeyguardDismissCallback callback) {
+    public void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message) {
         checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard");
         synchronized(mWindowMap) {
-            mPolicy.dismissKeyguardLw(callback);
+            mPolicy.dismissKeyguardLw(callback, message);
         }
     }
 
@@ -5327,6 +5327,25 @@
         reconfigureDisplayLocked(displayContent);
     }
 
+    @Override
+    public void startWindowTrace(){
+        try {
+            mWindowTracing.startTrace(null /* printwriter */);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void stopWindowTrace(){
+        mWindowTracing.stopTrace(null /* printwriter */);
+    }
+
+    @Override
+    public boolean isWindowTraceEnabled() {
+        return mWindowTracing.isEnabled();
+    }
+
     // -------------------------------------------------------------
     // Internals
     // -------------------------------------------------------------
@@ -5875,6 +5894,8 @@
      * the screen is.
      * @see WindowManagerPolicy#getNavBarPosition()
      */
+    @Override
+    @WindowManagerPolicy.NavigationBarPosition
     public int getNavBarPosition() {
         synchronized (mWindowMap) {
             // Perform layout if it was scheduled before to make sure that we get correct nav bar
@@ -6576,6 +6597,13 @@
         }
     }
 
+    public void onOverlayChanged() {
+        synchronized (mWindowMap) {
+            mPolicy.onOverlayChangedLw();
+            requestTraversal();
+        }
+    }
+
     public void onDisplayChanged(int displayId) {
         synchronized (mWindowMap) {
             final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index b9dc9db..e24c393 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -231,7 +231,7 @@
     }
 
     private int runDismissKeyguard(PrintWriter pw) throws RemoteException {
-        mInterface.dismissKeyguard(null /* callback */);
+        mInterface.dismissKeyguard(null /* callback */, null /* message */);
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0ad60c9..d068c49 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -20,6 +20,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.SurfaceControl.Transaction;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -30,6 +31,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
@@ -39,6 +41,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FORMAT_CHANGED;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -198,7 +202,6 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Comparator;
-import java.util.LinkedList;
 import java.util.function.Predicate;
 
 /** A window in the window manager. */
@@ -2977,7 +2980,33 @@
 
     /** @return true when the window is in fullscreen task, but has non-fullscreen bounds set. */
     boolean isLetterboxedAppWindow() {
-        return !isInMultiWindowMode() && mAppToken != null && !mAppToken.matchParentBounds();
+        return !isInMultiWindowMode() && mAppToken != null && !mAppToken.matchParentBounds()
+                || isLetterboxedForDisplayCutoutLw();
+    }
+
+    @Override
+    public boolean isLetterboxedForDisplayCutoutLw() {
+        if (mAppToken == null) {
+            // Only windows with an AppWindowToken are letterboxed.
+            return false;
+        }
+        if (getDisplayContent().getDisplayInfo().displayCutout == null) {
+            // No cutout, no letterbox.
+            return false;
+        }
+        if (mAttrs.layoutInDisplayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
+            // Layout in cutout, no letterbox.
+            return false;
+        }
+        // TODO: handle dialogs and other non-filling windows
+        if (mAttrs.layoutInDisplayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) {
+            // Never layout in cutout, always letterbox.
+            return true;
+        }
+        // Letterbox if any fullscreen mode is set.
+        final int fl = mAttrs.flags;
+        final int sysui = mSystemUiVisibility;
+        return (fl & FLAG_FULLSCREEN) != 0 || (sysui & (SYSTEM_UI_FLAG_FULLSCREEN)) != 0;
     }
 
     boolean isDragResizeChanged() {
@@ -3136,7 +3165,8 @@
         proto.end(token);
     }
 
-    void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
+    @Override
+    public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
         proto.write(USER_ID, UserHandle.getUserId(mOwnerUid));
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 96b0bd5..ba5156b 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -41,7 +41,6 @@
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
-import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
 import static com.android.server.wm.proto.WindowStateAnimatorProto.DRAW_STATE;
 import static com.android.server.wm.proto.WindowStateAnimatorProto.LAST_CLIP_RECT;
 import static com.android.server.wm.proto.WindowStateAnimatorProto.SURFACE;
@@ -1165,7 +1164,7 @@
                     // potentially occurring while turning off the screen. This would lead to the
                     // screen incorrectly turning back on.
                     if (!mService.mPowerManager.isInteractive()) {
-                        mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
+                        mService.mTurnOnScreen = true;
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index e26a362..2f38556 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -53,7 +53,7 @@
 
     final WindowStateAnimator mAnimator;
 
-    SurfaceControlWithBackground mSurfaceControl;
+    SurfaceControl mSurfaceControl;
 
     // Should only be set from within setShown().
     private boolean mSurfaceShown = false;
@@ -108,13 +108,11 @@
                 .setFormat(format)
                 .setFlags(flags)
                 .setMetadata(windowType, ownerUid);
-        mSurfaceControl = new SurfaceControlWithBackground(
-                name, b, windowType, w, h, this);
+        mSurfaceControl = b.build();
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
         if (mService.mRoot.mSurfaceTraceEnabled) {
-            mSurfaceControl = new RemoteSurfaceTrace(
-                    mService.mRoot.mSurfaceTraceFd.getFileDescriptor(), mSurfaceControl, win);
+            installRemoteTrace(mService.mRoot.mSurfaceTraceFd.getFileDescriptor());
         }
     }
 
@@ -123,7 +121,7 @@
     }
 
     void removeRemoteTrace() {
-        mSurfaceControl = new SurfaceControlWithBackground(mSurfaceControl);
+        mSurfaceControl = new SurfaceControl(mSurfaceControl);
     }
 
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index a512fdf..017b325 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -86,8 +86,7 @@
     static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
     static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
     static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
-    static final int SET_TURN_ON_SCREEN                 = 1 << 4;
-    static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
+    static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 4;
 
     private boolean mTraversalScheduled;
     private int mDeferDepth = 0;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index bad9bf5..172efdc 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,11 +16,7 @@
 
 package com.android.server.wm;
 
-import android.annotation.CallSuper;
-import android.util.proto.ProtoOutputStream;
-import java.util.Comparator;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -28,15 +24,20 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.proto.WindowTokenProto.HASH_CODE;
+import static com.android.server.wm.proto.WindowTokenProto.HIDDEN;
+import static com.android.server.wm.proto.WindowTokenProto.PAUSED;
+import static com.android.server.wm.proto.WindowTokenProto.WAITING_TO_SHOW;
 import static com.android.server.wm.proto.WindowTokenProto.WINDOWS;
 import static com.android.server.wm.proto.WindowTokenProto.WINDOW_CONTAINER;
 
+import android.annotation.CallSuper;
 import android.os.Debug;
 import android.os.IBinder;
 import android.util.Slog;
-import android.view.SurfaceControl;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.PrintWriter;
+import java.util.Comparator;
 
 /**
  * Container of a set of related windows in the window manager. Often this is an AppWindowToken,
@@ -276,6 +277,9 @@
             final WindowState w = mChildren.get(i);
             w.writeToProto(proto, WINDOWS, trim);
         }
+        proto.write(HIDDEN, mHidden);
+        proto.write(WAITING_TO_SHOW, waitingToShow);
+        proto.write(PAUSED, paused);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index c858b19..a299781 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -29,6 +29,7 @@
 import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.annotation.Nullable;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
@@ -62,7 +63,7 @@
         mTraceFile = file;
     }
 
-    void startTrace(PrintWriter pw) throws IOException {
+    void startTrace(@Nullable PrintWriter pw) throws IOException {
         if (IS_USER){
             logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
             return;
@@ -81,13 +82,15 @@
         }
     }
 
-    private void logAndPrintln(PrintWriter pw, String msg) {
+    private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
         Log.i(TAG, msg);
-        pw.println(msg);
-        pw.flush();
+        if (pw != null) {
+            pw.println(msg);
+            pw.flush();
+        }
     }
 
-    void stopTrace(PrintWriter pw) {
+    void stopTrace(@Nullable PrintWriter pw) {
         if (IS_USER){
             logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
             return;
diff --git a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java
new file mode 100644
index 0000000..09d7b5d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.utils;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.annotation.Dimension;
+import android.graphics.Matrix;
+import android.view.Surface.Rotation;
+
+public class CoordinateTransforms {
+
+    private CoordinateTransforms() {
+    }
+
+    /**
+     * Sets a matrix such that given a rotation, it transforms physical display
+     * coordinates to that rotation's logical coordinates.
+     *
+     * @param rotation the rotation to which the matrix should transform
+     * @param out      the matrix to be set
+     */
+    public static void transformPhysicalToLogicalCoordinates(@Rotation int rotation,
+            @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) {
+        switch (rotation) {
+            case ROTATION_0:
+                out.reset();
+                break;
+            case ROTATION_90:
+                out.setRotate(270);
+                out.postTranslate(0, physicalWidth);
+                break;
+            case ROTATION_180:
+                out.setRotate(180);
+                out.postTranslate(physicalWidth, physicalHeight);
+                break;
+            case ROTATION_270:
+                out.setRotate(90);
+                out.postTranslate(physicalHeight, 0);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown rotation: " + rotation);
+        }
+    }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index c1e95eb..36de3d1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -19,6 +19,7 @@
 import android.app.admin.IDevicePolicyManager;
 import android.content.ComponentName;
 import android.os.PersistableBundle;
+import android.os.UserHandle;
 import android.security.keymaster.KeymasterCertificateChain;
 import android.security.keystore.ParcelableKeyGenParameterSpec;
 
@@ -38,6 +39,12 @@
  */
 abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
     /**
+     * To be called by {@link DevicePolicyManagerService#Lifecycle} when the service is started.
+     *
+     * @see {@link SystemService#onStart}.
+     */
+    abstract void handleStart();
+    /**
      * To be called by {@link DevicePolicyManagerService#Lifecycle} during the various boot phases.
      *
      * @see {@link SystemService#onBootPhase}.
@@ -64,7 +71,7 @@
 
     public void setSystemSetting(ComponentName who, String setting, String value){}
 
-    public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {}
+    public void transferOwnership(ComponentName admin, ComponentName target, PersistableBundle bundle) {}
 
     public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm,
             ParcelableKeyGenParameterSpec keySpec, int idAttestationFlags,
@@ -97,4 +104,9 @@
             byte[] cert, byte[] chain, boolean isUserSelectable) {
         return false;
     }
+
+    @Override
+    public boolean startUserInBackground(ComponentName who, UserHandle userHandle) {
+        return false;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f0681e9..38d423d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -20,6 +20,7 @@
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.USER_OP_SUCCESS;
+import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
 import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
 import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED;
@@ -53,7 +54,6 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
-import static android.app.admin.DevicePolicyManager.START_USER_IN_BACKGROUND;
 import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
@@ -95,6 +95,7 @@
 import android.app.admin.SystemUpdatePolicy;
 import android.app.backup.IBackupManager;
 import android.app.trust.TrustManager;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -149,12 +150,12 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.os.storage.StorageManager;
 import android.provider.ContactsContract.QuickContact;
 import android.provider.ContactsInternal;
 import android.provider.Settings;
 import android.provider.Settings.Global;
-import android.security.Credentials;
 import android.security.IKeyChainAliasCallback;
 import android.security.IKeyChainService;
 import android.security.KeyChain;
@@ -225,6 +226,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -401,6 +403,7 @@
     final IPackageManager mIPackageManager;
     final UserManager mUserManager;
     final UserManagerInternal mUserManagerInternal;
+    final UsageStatsManagerInternal mUsageStatsManagerInternal;
     final TelephonyManager mTelephonyManager;
     private final LockPatternUtils mLockPatternUtils;
     private final DevicePolicyConstants mConstants;
@@ -504,6 +507,7 @@
         @Override
         public void onStart() {
             publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
+            mService.handleStart();
         }
 
         @Override
@@ -700,6 +704,33 @@
         }
     };
 
+    protected static class RestrictionsListener implements UserRestrictionsListener {
+        private Context mContext;
+
+        public RestrictionsListener(Context context) {
+            mContext = context;
+        }
+
+        public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
+                Bundle prevRestrictions) {
+            final boolean newlyDisallowed =
+                    newRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE);
+            final boolean previouslyDisallowed =
+                    prevRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE);
+            final boolean restrictionChanged = (newlyDisallowed != previouslyDisallowed);
+
+            if (restrictionChanged) {
+                // Notify ManagedProvisioning to update the built-in cross profile intent filters.
+                Intent intent = new Intent(
+                        DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_CHANGED);
+                intent.setPackage(MANAGED_PROVISIONING_PKG);
+                intent.putExtra(Intent.EXTRA_USER_ID, userId);
+                intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+            }
+        }
+    }
+
     static class ActiveAdmin {
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
         private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin";
@@ -760,6 +791,7 @@
         private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
         private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
         private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled";
+        private static final String TAG_MANDATORY_BACKUP_TRANSPORT = "mandatory_backup_transport";
 
         DeviceAdminInfo info;
 
@@ -876,6 +908,10 @@
         // The blacklist data is stored in a file whose name is stored in the XML
         String passwordBlacklistFile = null;
 
+        // The component name of the backup transport which has to be used if backups are mandatory
+        // or null if backups are not mandatory.
+        ComponentName mandatoryBackupTransport = null;
+
         ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
             info = _info;
             isParent = parent;
@@ -1139,6 +1175,11 @@
                 out.attribute(null, ATTR_VALUE, Boolean.toString(isLogoutEnabled));
                 out.endTag(null, TAG_IS_LOGOUT_ENABLED);
             }
+            if (mandatoryBackupTransport != null) {
+                out.startTag(null, TAG_MANDATORY_BACKUP_TRANSPORT);
+                out.attribute(null, ATTR_VALUE, mandatoryBackupTransport.flattenToString());
+                out.endTag(null, TAG_MANDATORY_BACKUP_TRANSPORT);
+            }
         }
 
         void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -1317,6 +1358,9 @@
                 } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) {
                     isLogoutEnabled = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MANDATORY_BACKUP_TRANSPORT.equals(tag)) {
+                    mandatoryBackupTransport = ComponentName.unflattenFromString(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1560,6 +1604,7 @@
                             removedAdmin = true;
                             policy.mAdminList.remove(i);
                             policy.mAdminMap.remove(aa.info.getComponent());
+                            pushActiveAdminPackagesLocked(userHandle);
                         }
                     }
                 } catch (RemoteException re) {
@@ -1653,6 +1698,10 @@
             return LocalServices.getService(PackageManagerInternal.class);
         }
 
+        UsageStatsManagerInternal getUsageStatsManagerInternal() {
+            return LocalServices.getService(UsageStatsManagerInternal.class);
+        }
+
         NotificationManager getNotificationManager() {
             return mContext.getSystemService(NotificationManager.class);
         }
@@ -1691,6 +1740,10 @@
             return ActivityManager.getService();
         }
 
+        ActivityManagerInternal getActivityManagerInternal() {
+            return LocalServices.getService(ActivityManagerInternal.class);
+        }
+
         IPackageManager getIPackageManager() {
             return AppGlobals.getPackageManager();
         }
@@ -1923,6 +1976,8 @@
 
         mUserManager = Preconditions.checkNotNull(injector.getUserManager());
         mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
+        mUsageStatsManagerInternal = Preconditions.checkNotNull(
+                injector.getUsageStatsManagerInternal());
         mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
         mTelephonyManager = Preconditions.checkNotNull(injector.getTelephonyManager());
 
@@ -1972,6 +2027,8 @@
         LocalServices.addService(DevicePolicyManagerInternal.class, mLocalService);
 
         mSetupContentObserver = new SetupContentObserver(mHandler);
+
+        mUserManagerInternal.addUserRestrictionsListener(new RestrictionsListener(mContext));
     }
 
     /**
@@ -3190,6 +3247,11 @@
     }
 
     @Override
+    void handleStart() {
+        pushActiveAdminPackages();
+    }
+
+    @Override
     void handleStartUser(int userId) {
         updateScreenCaptureDisabledInWindowManager(userId,
                 getScreenCaptureDisabled(null, userId));
@@ -3357,6 +3419,8 @@
                 if (replaceIndex == -1) {
                     policy.mAdminList.add(newAdmin);
                     enableIfNecessary(info.getPackageName(), userHandle);
+                    mUsageStatsManagerInternal.onActiveAdminAdded(
+                            adminReceiver.getPackageName(), userHandle);
                 } else {
                     policy.mAdminList.set(replaceIndex, newAdmin);
                 }
@@ -3369,6 +3433,35 @@
         }
     }
 
+    private void pushActiveAdminPackages() {
+        synchronized (this) {
+            final List<UserInfo> users = mUserManager.getUsers();
+            for (int i = users.size() - 1; i >= 0; --i) {
+                final int userId = users.get(i).id;
+                mUsageStatsManagerInternal.setActiveAdminApps(
+                        getActiveAdminPackagesLocked(userId), userId);
+            }
+        }
+    }
+
+    private void pushActiveAdminPackagesLocked(int userId) {
+        mUsageStatsManagerInternal.setActiveAdminApps(
+                getActiveAdminPackagesLocked(userId), userId);
+    }
+
+    private Set<String> getActiveAdminPackagesLocked(int userId) {
+        final DevicePolicyData policy = getUserData(userId);
+        Set<String> adminPkgs = null;
+        for (int i = policy.mAdminList.size() - 1; i >= 0; --i) {
+            final String pkgName = policy.mAdminList.get(i).info.getPackageName();
+            if (adminPkgs == null) {
+                adminPkgs = new ArraySet<>();
+            }
+            adminPkgs.add(pkgName);
+        }
+        return adminPkgs;
+    }
+
     private void transferActiveAdminUncheckedLocked(ComponentName incomingReceiver,
             ComponentName outgoingReceiver, int userHandle) {
         final DevicePolicyData policy = getUserData(userHandle);
@@ -3487,6 +3580,7 @@
         }
     }
 
+    @Override
     public void forceRemoveActiveAdmin(ComponentName adminReceiver, int userHandle) {
         if (!mHasFeature) {
             return;
@@ -3540,7 +3634,7 @@
     private boolean isPackageTestOnly(String packageName, int userHandle) {
         final ApplicationInfo ai;
         try {
-            ai = mIPackageManager.getApplicationInfo(packageName,
+            ai = mInjector.getIPackageManager().getApplicationInfo(packageName,
                     (PackageManager.MATCH_DIRECT_BOOT_AWARE
                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), userHandle);
         } catch (RemoteException e) {
@@ -3562,7 +3656,7 @@
     }
 
     private void enforceShell(String method) {
-        final int callingUid = Binder.getCallingUid();
+        final int callingUid = mInjector.binderGetCallingUid();
         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
             throw new SecurityException("Non-shell user attempted to call " + method);
         }
@@ -6506,13 +6600,36 @@
         }
     }
 
-    synchronized void sendDeviceOwnerCommand(String action, Bundle extras) {
-        Intent intent = new Intent(action);
-        intent.setComponent(mOwners.getDeviceOwnerComponent());
+    void sendDeviceOwnerCommand(String action, Bundle extras) {
+        int deviceOwnerUserId;
+        ComponentName deviceOwnerComponent;
+        synchronized (this) {
+            deviceOwnerUserId = mOwners.getDeviceOwnerUserId();
+            deviceOwnerComponent = mOwners.getDeviceOwnerComponent();
+        }
+        sendActiveAdminCommand(action, extras, deviceOwnerUserId,
+                deviceOwnerComponent);
+    }
+
+    private void sendProfileOwnerCommand(String action, Bundle extras, int userHandle) {
+        sendActiveAdminCommand(action, extras, userHandle,
+                mOwners.getProfileOwnerComponent(userHandle));
+    }
+
+    private void sendActiveAdminCommand(String action, Bundle extras,
+            int userHandle, ComponentName receiverComponent) {
+        final Intent intent = new Intent(action);
+        intent.setComponent(receiverComponent);
         if (extras != null) {
             intent.putExtras(extras);
         }
-        mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
+        mContext.sendBroadcastAsUser(intent, UserHandle.of(userHandle));
+    }
+
+    private void sendOwnerChangedBroadcast(String broadcast, int userId) {
+        final Intent intent = new Intent(broadcast)
+                .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
     }
 
     private synchronized String getDeviceOwnerRemoteBugreportUri() {
@@ -6890,10 +7007,7 @@
             ident = mInjector.binderClearCallingIdentity();
             try {
                 // TODO Send to system too?
-                mContext.sendBroadcastAsUser(
-                        new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED)
-                                .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
-                        UserHandle.of(userId));
+                sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
@@ -7044,9 +7158,8 @@
             try {
                 clearDeviceOwnerLocked(admin, deviceOwnerUserId);
                 removeActiveAdminLocked(deviceOwnerComponent, deviceOwnerUserId);
-                Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
-                intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-                mContext.sendBroadcastAsUser(intent, UserHandle.of(deviceOwnerUserId));
+                sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED,
+                        deviceOwnerUserId);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
@@ -7131,6 +7244,8 @@
                     ensureUnknownSourcesRestrictionForProfileOwnerLocked(userHandle, admin,
                             true /* newOwner */);
                 }
+                sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED,
+                        userHandle);
             } finally {
                 mInjector.binderRestoreCallingIdentity(id);
             }
@@ -7159,6 +7274,8 @@
             try {
                 clearProfileOwnerLocked(admin, userId);
                 removeActiveAdminLocked(who, userId);
+                sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED,
+                        userId);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
@@ -8541,14 +8658,6 @@
                         Settings.Secure.USER_SETUP_COMPLETE, 1, userHandle);
             }
 
-            if ((flags & START_USER_IN_BACKGROUND) != 0) {
-                try {
-                    mInjector.getIActivityManager().startUserInBackground(userHandle);
-                } catch (RemoteException re) {
-                    // Does not happen, same process
-                }
-            }
-
             return user;
         } catch (Throwable re) {
             mUserManager.removeUser(userHandle);
@@ -8561,6 +8670,8 @@
     @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
         Preconditions.checkNotNull(who, "ComponentName is null");
+        Preconditions.checkNotNull(userHandle, "UserHandle is null");
+
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
         }
@@ -8599,6 +8710,7 @@
     @Override
     public boolean switchUser(ComponentName who, UserHandle userHandle) {
         Preconditions.checkNotNull(who, "ComponentName is null");
+
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
@@ -8619,8 +8731,40 @@
     }
 
     @Override
+    public boolean startUserInBackground(ComponentName who, UserHandle userHandle) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        Preconditions.checkNotNull(userHandle, "UserHandle is null");
+
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+
+        final int userId = userHandle.getIdentifier();
+        if (isManagedProfile(userId)) {
+            Log.w(LOG_TAG, "Managed profile cannot be started in background");
+            return false;
+        }
+
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) {
+                Log.w(LOG_TAG, "Cannot start more users in background");
+                return false;
+            }
+
+            return mInjector.getIActivityManager().startUserInBackground(userId);
+        } catch (RemoteException e) {
+            // Same process, should not happen.
+            return false;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+    }
+
+    @Override
     public boolean stopUser(ComponentName who, UserHandle userHandle) {
         Preconditions.checkNotNull(who, "ComponentName is null");
+        Preconditions.checkNotNull(userHandle, "UserHandle is null");
 
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -9669,7 +9813,7 @@
                 return false;
             }
             mLockPatternUtils.setLockScreenDisabled(disabled, userId);
-            mInjector.getIWindowManager().dismissKeyguard(null);
+            mInjector.getIWindowManager().dismissKeyguard(null /* callback */, null /* message */);
         } catch (RemoteException e) {
             // Same process, does not happen.
         } finally {
@@ -11140,6 +11284,7 @@
             if (doProxyCleanup) {
                 resetGlobalProxyLocked(policy);
             }
+            pushActiveAdminPackagesLocked(userHandle);
             saveSettingsLocked(userHandle);
             updateMaximumTimeToLockLocked(userHandle);
             policy.mRemovingAdmins.remove(adminReceiver);
@@ -11206,7 +11351,12 @@
         }
         Preconditions.checkNotNull(admin);
         synchronized (this) {
-            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(
+                    admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            if (!enabled) {
+                activeAdmin.mandatoryBackupTransport = null;
+                saveSettingsLocked(UserHandle.USER_SYSTEM);
+            }
         }
 
         final long ident = mInjector.binderClearCallingIdentity();
@@ -11241,6 +11391,50 @@
     }
 
     @Override
+    public void setMandatoryBackupTransport(
+            ComponentName admin, ComponentName backupTransportComponent) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(admin);
+        synchronized (this) {
+            ActiveAdmin activeAdmin =
+                    getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            if (!Objects.equals(backupTransportComponent, activeAdmin.mandatoryBackupTransport)) {
+                activeAdmin.mandatoryBackupTransport = backupTransportComponent;
+                saveSettingsLocked(UserHandle.USER_SYSTEM);
+            }
+        }
+        final long identity = mInjector.binderClearCallingIdentity();
+        try {
+            IBackupManager ibm = mInjector.getIBackupManager();
+            if (ibm != null && backupTransportComponent != null) {
+                if (!ibm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
+                    ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+                }
+                ibm.selectBackupTransportAsync(backupTransportComponent, null);
+                ibm.setBackupEnabled(true);
+            }
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to set mandatory backup transport.", e);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public ComponentName getMandatoryBackupTransport() {
+        if (!mHasFeature) {
+            return null;
+        }
+        synchronized (this) {
+            ActiveAdmin activeAdmin = getDeviceOwnerAdminLocked();
+            return activeAdmin == null ? null : activeAdmin.mandatoryBackupTransport;
+        }
+    }
+
+
+    @Override
     public boolean bindDeviceAdminServiceAsUser(
             @NonNull ComponentName admin, @NonNull IApplicationThread caller,
             @Nullable IBinder activtiyToken, @NonNull Intent serviceIntent,
@@ -11847,9 +12041,9 @@
     }
 
     //TODO: Add callback information to the javadoc once it is completed.
-    //TODO: Make transferOwner atomic.
+    //TODO: Make transferOwnership atomic.
     @Override
-    public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {
+    public void transferOwnership(ComponentName admin, ComponentName target, PersistableBundle bundle) {
         if (!mHasFeature) {
             return;
         }
@@ -11877,13 +12071,12 @@
 
         final long id = mInjector.binderClearCallingIdentity();
         try {
-            //STOPSHIP add support for COMP, edge cases when device is rebooted/work mode off,
-            //transfer callbacks and broadcast
+            //STOPSHIP add support for COMP, edge cases when device is rebooted/work mode off
             synchronized (this) {
                 if (isProfileOwner(admin, callingUserId)) {
-                    transferProfileOwnerLocked(admin, target, callingUserId);
+                    transferProfileOwnerLocked(admin, target, callingUserId, bundle);
                 } else if (isDeviceOwner(admin, callingUserId)) {
-                    transferDeviceOwnerLocked(admin, target, callingUserId);
+                    transferDeviceOwnerLocked(admin, target, callingUserId, bundle);
                 }
             }
         } finally {
@@ -11895,24 +12088,40 @@
      * Transfers the profile owner for user with id profileOwnerUserId from admin to target.
      */
     private void transferProfileOwnerLocked(ComponentName admin, ComponentName target,
-            int profileOwnerUserId) {
+            int profileOwnerUserId, PersistableBundle bundle) {
         transferActiveAdminUncheckedLocked(target, admin, profileOwnerUserId);
         mOwners.transferProfileOwner(target, profileOwnerUserId);
         Slog.i(LOG_TAG, "Profile owner set: " + target + " on user " + profileOwnerUserId);
         mOwners.writeProfileOwner(profileOwnerUserId);
         mDeviceAdminServiceController.startServiceForOwner(
                 target.getPackageName(), profileOwnerUserId, "transfer-profile-owner");
+        sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_TRANSFER_OWNERSHIP_COMPLETE,
+                getTransferOwnerAdminExtras(bundle), profileOwnerUserId);
+        sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED,
+                profileOwnerUserId);
     }
 
     /**
      * Transfers the device owner for user with id userId from admin to target.
      */
-    private void transferDeviceOwnerLocked(ComponentName admin, ComponentName target, int userId) {
+    private void transferDeviceOwnerLocked(ComponentName admin, ComponentName target, int userId,
+            PersistableBundle bundle) {
         transferActiveAdminUncheckedLocked(target, admin, userId);
         mOwners.transferDeviceOwner(target);
         Slog.i(LOG_TAG, "Device owner set: " + target + " on user " + userId);
         mOwners.writeDeviceOwner();
         mDeviceAdminServiceController.startServiceForOwner(
                 target.getPackageName(), userId, "transfer-device-owner");
+        sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_TRANSFER_OWNERSHIP_COMPLETE,
+                getTransferOwnerAdminExtras(bundle));
+        sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId);
+    }
+
+    private Bundle getTransferOwnerAdminExtras(PersistableBundle bundle) {
+        Bundle extras = new Bundle();
+        if (bundle != null) {
+            extras.putParcelable(EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE, bundle);
+        }
+        return extras;
     }
 }
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 31a1abb..7d9736e 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -38,6 +38,7 @@
 import android.net.metrics.ApfStats;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.RaEvent;
+import android.net.util.InterfaceParams;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.PacketSocketAddress;
@@ -56,7 +57,6 @@
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
-import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
@@ -247,7 +247,7 @@
 
     private final ApfCapabilities mApfCapabilities;
     private final IpClient.Callback mIpClientCallback;
-    private final NetworkInterface mNetworkInterface;
+    private final InterfaceParams mInterfaceParams;
     private final IpConnectivityLog mMetricsLog;
 
     @VisibleForTesting
@@ -269,11 +269,11 @@
     private int mIPv4PrefixLength;
 
     @VisibleForTesting
-    ApfFilter(ApfConfiguration config, NetworkInterface networkInterface,
+    ApfFilter(ApfConfiguration config, InterfaceParams ifParams,
             IpClient.Callback ipClientCallback, IpConnectivityLog log) {
         mApfCapabilities = config.apfCapabilities;
         mIpClientCallback = ipClientCallback;
-        mNetworkInterface = networkInterface;
+        mInterfaceParams = ifParams;
         mMulticastFilter = config.multicastFilter;
         mDrop802_3Frames = config.ieee802_3Filter;
 
@@ -287,7 +287,7 @@
     }
 
     private void log(String s) {
-        Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s);
+        Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
     }
 
     @GuardedBy("this")
@@ -332,14 +332,14 @@
     void maybeStartFilter() {
         FileDescriptor socket;
         try {
-            mHardwareAddress = mNetworkInterface.getHardwareAddress();
+            mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
             synchronized(this) {
                 // Install basic filters
                 installNewProgramLocked();
             }
             socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
-            PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6,
-                    mNetworkInterface.getIndex());
+            PacketSocketAddress addr = new PacketSocketAddress(
+                    (short) ETH_P_IPV6, mInterfaceParams.index);
             Os.bind(socket, addr);
             NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
         } catch(SocketException|ErrnoException e) {
@@ -1168,10 +1168,10 @@
      * filtering using APF programs.
      */
     public static ApfFilter maybeCreate(ApfConfiguration config,
-            NetworkInterface networkInterface, IpClient.Callback ipClientCallback) {
-        if (config == null) return null;
+            InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
+        if (config == null || ifParams == null) return null;
         ApfCapabilities apfCapabilities =  config.apfCapabilities;
-        if (apfCapabilities == null || networkInterface == null) return null;
+        if (apfCapabilities == null) return null;
         if (apfCapabilities.apfVersionSupported == 0) return null;
         if (apfCapabilities.maximumApfProgramSize < 512) {
             Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
@@ -1186,7 +1186,7 @@
             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
             return null;
         }
-        return new ApfFilter(config, networkInterface, ipClientCallback, new IpConnectivityLog());
+        return new ApfFilter(config, ifParams, ipClientCallback, new IpConnectivityLog());
     }
 
     public synchronized void shutdown() {
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index ed78175..a956cef 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -34,6 +34,7 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.DhcpClientEvent;
 import android.net.metrics.DhcpErrorEvent;
+import android.net.util.InterfaceParams;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -50,7 +51,6 @@
 import java.io.IOException;
 import java.lang.Thread;
 import java.net.Inet4Address;
-import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -187,7 +187,8 @@
     private final String mIfaceName;
 
     private boolean mRegisteredForPreDhcpNotification;
-    private NetworkInterface mIface;
+    private InterfaceParams mIface;
+    // TODO: MacAddress-ify more of this class hierarchy.
     private byte[] mHwAddr;
     private PacketSocketAddress mInterfaceBroadcastAddr;
     private int mTransactionId;
@@ -221,8 +222,9 @@
         return new WakeupMessage(mContext, getHandler(), cmdName, cmd);
     }
 
+    // TODO: Take an InterfaceParams instance instead of an interface name String.
     private DhcpClient(Context context, StateMachine controller, String iface) {
-        super(TAG);
+        super(TAG, controller.getHandler());
 
         mContext = context;
         mController = controller;
@@ -262,23 +264,23 @@
     }
 
     public static DhcpClient makeDhcpClient(
-            Context context, StateMachine controller, String intf) {
-        DhcpClient client = new DhcpClient(context, controller, intf);
+            Context context, StateMachine controller, InterfaceParams ifParams) {
+        DhcpClient client = new DhcpClient(context, controller, ifParams.name);
+        client.mIface = ifParams;
         client.start();
         return client;
     }
 
     private boolean initInterface() {
-        try {
-            mIface = NetworkInterface.getByName(mIfaceName);
-            mHwAddr = mIface.getHardwareAddress();
-            mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.getIndex(),
-                    DhcpPacket.ETHER_BROADCAST);
-            return true;
-        } catch(SocketException | NullPointerException e) {
-            Log.e(TAG, "Can't determine ifindex or MAC address for " + mIfaceName, e);
+        if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName);
+        if (mIface == null) {
+            Log.e(TAG, "Can't determine InterfaceParams for " + mIfaceName);
             return false;
         }
+
+        mHwAddr = mIface.macAddr.toByteArray();
+        mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.index, DhcpPacket.ETHER_BROADCAST);
+        return true;
     }
 
     private void startNewTransaction() {
@@ -293,7 +295,7 @@
     private boolean initPacketSocket() {
         try {
             mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP);
-            PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.getIndex());
+            PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.index);
             Os.bind(mPacketSock, addr);
             NetworkUtils.attachDhcpFilter(mPacketSock);
         } catch(SocketException|ErrnoException e) {
diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
index 6cf4fa9a..e6ddbbc 100644
--- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java
+++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
@@ -21,6 +21,7 @@
 import android.net.NetworkUtils;
 import android.net.util.PacketReader;
 import android.net.util.ConnectivityPacketSummary;
+import android.net.util.InterfaceParams;
 import android.os.Handler;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -35,7 +36,6 @@
 import java.io.FileDescriptor;
 import java.io.InterruptedIOException;
 import java.io.IOException;
-import java.net.NetworkInterface;
 import java.net.SocketException;
 
 
@@ -69,24 +69,12 @@
     private boolean mRunning;
     private String mDisplayName;
 
-    public ConnectivityPacketTracker(Handler h, NetworkInterface netif, LocalLog log) {
-        final String ifname;
-        final int ifindex;
-        final byte[] hwaddr;
-        final int mtu;
+    public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) {
+        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
 
-        try {
-            ifname = netif.getName();
-            ifindex = netif.getIndex();
-            hwaddr = netif.getHardwareAddress();
-            mtu = netif.getMTU();
-        } catch (NullPointerException|SocketException e) {
-            throw new IllegalArgumentException("bad network interface", e);
-        }
-
-        mTag = TAG + "." + ifname;
+        mTag = TAG + "." + ifParams.name;
         mLog = log;
-        mPacketListener = new PacketListener(h, ifindex, hwaddr, mtu);
+        mPacketListener = new PacketListener(h, ifParams);
     }
 
     public void start(String displayName) {
@@ -102,13 +90,11 @@
     }
 
     private final class PacketListener extends PacketReader {
-        private final int mIfIndex;
-        private final byte mHwAddr[];
+        private final InterfaceParams mInterface;
 
-        PacketListener(Handler h, int ifindex, byte[] hwaddr, int mtu) {
-            super(h, mtu);
-            mIfIndex = ifindex;
-            mHwAddr = hwaddr;
+        PacketListener(Handler h, InterfaceParams ifParams) {
+            super(h, ifParams.defaultMtu);
+            mInterface = ifParams;
         }
 
         @Override
@@ -117,7 +103,7 @@
             try {
                 s = Os.socket(AF_PACKET, SOCK_RAW, 0);
                 NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
-                Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mIfIndex));
+                Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mInterface.index));
             } catch (ErrnoException | IOException e) {
                 logError("Failed to create packet tracking socket: ", e);
                 closeFd(s);
@@ -129,7 +115,7 @@
         @Override
         protected void handlePacket(byte[] recvbuf, int length) {
             final String summary = ConnectivityPacketSummary.summarize(
-                    mHwAddr, recvbuf, length);
+                    mInterface.macAddr, recvbuf, length);
             if (summary == null) return;
 
             if (DBG) Log.d(mTag, summary);
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index fdb366c..d3a97b3 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -35,6 +35,7 @@
 import android.net.dhcp.DhcpClient;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpManagerEvent;
+import android.net.util.InterfaceParams;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
 import android.net.util.NetworkConstants;
@@ -63,7 +64,6 @@
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
-import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -556,7 +556,7 @@
     private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
     private final InterfaceController mInterfaceCtrl;
 
-    private NetworkInterface mNetworkInterface;
+    private InterfaceParams mInterfaceParams;
 
     /**
      * Non-final member variables accessed only from within our StateMachine.
@@ -722,7 +722,12 @@
             return;
         }
 
-        getNetworkInterface();
+        mInterfaceParams = InterfaceParams.getByName(mInterfaceName);
+        if (mInterfaceParams == null) {
+            logError("Failed to find InterfaceParams for " + mInterfaceName);
+            // TODO: call doImmediateProvisioningFailure() with an error code
+            // indicating something like "interface not ready".
+        }
 
         mCallback.setNeighborDiscoveryOffload(true);
         sendMessage(CMD_START, new ProvisioningConfiguration(req));
@@ -858,7 +863,7 @@
     protected String getLogRecString(Message msg) {
         final String logLine = String.format(
                 "%s/%d %d %d %s [%s]",
-                mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(),
+                mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index,
                 msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
 
         final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
@@ -889,15 +894,6 @@
         mLog.log(msg);
     }
 
-    private void getNetworkInterface() {
-        try {
-            mNetworkInterface = NetworkInterface.getByName(mInterfaceName);
-        } catch (SocketException | NullPointerException e) {
-            // TODO: throw new IllegalStateException.
-            logError("Failed to get interface object: %s", e);
-        }
-    }
-
     // This needs to be called with care to ensure that our LinkProperties
     // are in sync with the actual LinkProperties of the interface. For example,
     // we should only call this if we know for sure that there are no IP addresses
@@ -1218,7 +1214,7 @@
             }
         } else {
             // Start DHCPv4.
-            mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceName);
+            mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
             mDhcpClient.registerForPreDhcpNotification();
             mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
         }
@@ -1245,7 +1241,7 @@
         try {
             mIpReachabilityMonitor = new IpReachabilityMonitor(
                     mContext,
-                    mInterfaceName,
+                    mInterfaceParams,
                     getHandler(),
                     mLog,
                     new IpReachabilityMonitor.Callback() {
@@ -1447,7 +1443,7 @@
                     mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
             apfConfig.ethTypeBlackList =
                     mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
-            mApfFilter = ApfFilter.maybeCreate(apfConfig, mNetworkInterface, mCallback);
+            mApfFilter = ApfFilter.maybeCreate(apfConfig, mInterfaceParams, mCallback);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
             // rest of this IP configuration startup.
             if (mApfFilter == null) {
@@ -1515,7 +1511,7 @@
         private ConnectivityPacketTracker createPacketTracker() {
             try {
                 return new ConnectivityPacketTracker(
-                        getHandler(), mNetworkInterface, mConnectivityPacketLog);
+                        getHandler(), mInterfaceParams, mConnectivityPacketLog);
             } catch (IllegalArgumentException e) {
                 return null;
             }
diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java
index 6807334..fc07aa1 100644
--- a/services/net/java/android/net/ip/IpNeighborMonitor.java
+++ b/services/net/java/android/net/ip/IpNeighborMonitor.java
@@ -16,7 +16,11 @@
 
 package android.net.ip;
 
-import android.net.netlink.NetlinkConstants;
+import static android.net.netlink.NetlinkConstants.hexify;
+import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH;
+import static android.net.netlink.NetlinkConstants.stringForNlMsgType;
+
+import android.net.MacAddress;
 import android.net.netlink.NetlinkErrorMessage;
 import android.net.netlink.NetlinkMessage;
 import android.net.netlink.NetlinkSocket;
@@ -92,37 +96,35 @@
         final int ifindex;
         final InetAddress ip;
         final short nudState;
-        final byte[] linkLayerAddr;
+        final MacAddress macAddr;
 
         public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip,
-                short nudState, byte[] linkLayerAddr) {
+                short nudState, MacAddress macAddr) {
             this.elapsedMs = elapsedMs;
             this.msgType = msgType;
             this.ifindex = ifindex;
             this.ip = ip;
             this.nudState = nudState;
-            this.linkLayerAddr = linkLayerAddr;
+            this.macAddr = macAddr;
         }
 
         boolean isConnected() {
-            return (msgType != NetlinkConstants.RTM_DELNEIGH) &&
-                   StructNdMsg.isNudStateConnected(nudState);
+            return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState);
         }
 
         boolean isValid() {
-            return (msgType != NetlinkConstants.RTM_DELNEIGH) &&
-                   StructNdMsg.isNudStateValid(nudState);
+            return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState);
         }
 
         @Override
         public String toString() {
             final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}");
             return j.add("@" + elapsedMs)
-                    .add(NetlinkConstants.stringForNlMsgType(msgType))
+                    .add(stringForNlMsgType(msgType))
                     .add("if=" + ifindex)
                     .add(ip.getHostAddress())
                     .add(StructNdMsg.stringForNudState(nudState))
-                    .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]")
+                    .add("[" + macAddr + "]")
                     .toString();
         }
     }
@@ -183,7 +185,7 @@
             final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
             if (nlMsg == null || nlMsg.getHeader() == null) {
                 byteBuffer.position(position);
-                mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
+                mLog.e("unparsable netlink msg: " + hexify(byteBuffer));
                 break;
             }
 
@@ -217,12 +219,13 @@
         final int ifindex = ndMsg.ndm_ifindex;
         final InetAddress destination = neighMsg.getDestination();
         final short nudState =
-                (msgType == NetlinkConstants.RTM_DELNEIGH)
+                (msgType == RTM_DELNEIGH)
                 ? StructNdMsg.NUD_NONE
                 : ndMsg.ndm_state;
 
         final NeighborEvent event = new NeighborEvent(
-                whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress());
+                whenMs, msgType, ifindex, destination, nudState,
+                getMacAddress(neighMsg.getLinkLayerAddress()));
 
         if (VDBG) {
             Log.d(TAG, neighMsg.toString());
@@ -233,4 +236,16 @@
 
         mConsumer.accept(event);
     }
+
+    private static MacAddress getMacAddress(byte[] linkLayerAddress) {
+        if (linkLayerAddress != null) {
+            try {
+                return MacAddress.fromBytes(linkLayerAddress);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress));
+            }
+        }
+
+        return null;
+    }
 }
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index b31ffbb..7e02a28 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -26,6 +26,7 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpReachabilityEvent;
 import android.net.netlink.StructNdMsg;
+import android.net.util.InterfaceParams;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.SharedLog;
 import android.os.Handler;
@@ -46,9 +47,7 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
-import java.net.NetworkInterface;
 import java.net.SocketAddress;
-import java.net.SocketException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -168,8 +167,7 @@
         }
     }
 
-    private final String mInterfaceName;
-    private final int mInterfaceIndex;
+    private final InterfaceParams mInterfaceParams;
     private final IpNeighborMonitor mIpNeighborMonitor;
     private final SharedLog mLog;
     private final Callback mCallback;
@@ -182,30 +180,25 @@
     private volatile long mLastProbeTimeMs;
 
     public IpReachabilityMonitor(
-            Context context, String ifName, Handler h, SharedLog log, Callback callback) {
-        this(context, ifName, h, log, callback, null);
-    }
-
-    public IpReachabilityMonitor(
-            Context context, String ifName, Handler h, SharedLog log, Callback callback,
+            Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
             MultinetworkPolicyTracker tracker) {
-        this(ifName, getInterfaceIndex(ifName), h, log, callback, tracker,
-                Dependencies.makeDefault(context, ifName));
+        this(ifParams, h, log, callback, tracker, Dependencies.makeDefault(context, ifParams.name));
     }
 
     @VisibleForTesting
-    IpReachabilityMonitor(String ifName, int ifIndex, Handler h, SharedLog log, Callback callback,
+    IpReachabilityMonitor(InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
             MultinetworkPolicyTracker tracker, Dependencies dependencies) {
-        mInterfaceName = ifName;
+        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
+
+        mInterfaceParams = ifParams;
         mLog = log.forSubComponent(TAG);
         mCallback = callback;
         mMultinetworkPolicyTracker = tracker;
-        mInterfaceIndex = ifIndex;
         mDependencies = dependencies;
 
         mIpNeighborMonitor = new IpNeighborMonitor(h, mLog,
                 (NeighborEvent event) -> {
-                    if (mInterfaceIndex != event.ifindex) return;
+                    if (mInterfaceParams.index != event.ifindex) return;
                     if (!mNeighborWatchList.containsKey(event.ip)) return;
 
                     final NeighborEvent prev = mNeighborWatchList.put(event.ip, event);
@@ -241,7 +234,7 @@
 
     private String describeWatchList(String sep) {
         final StringBuilder sb = new StringBuilder();
-        sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}," + sep);
+        sb.append("iface{" + mInterfaceParams + "}," + sep);
         sb.append("ntable=[" + sep);
         String delimiter = "";
         for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
@@ -262,10 +255,10 @@
     }
 
     public void updateLinkProperties(LinkProperties lp) {
-        if (!mInterfaceName.equals(lp.getInterfaceName())) {
+        if (!mInterfaceParams.name.equals(lp.getInterfaceName())) {
             // TODO: figure out whether / how to cope with interface changes.
             Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() +
-                    "' does not match: " + mInterfaceName);
+                    "' does not match: " + mInterfaceParams.name);
             return;
         }
 
@@ -353,10 +346,10 @@
             mDependencies.acquireWakeLock(getProbeWakeLockDuration());
         }
 
-        for (InetAddress target : ipProbeList) {
-            final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceIndex, target);
+        for (InetAddress ip : ipProbeList) {
+            final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceParams.index, ip);
             mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)",
-                     target.getHostAddress(), rval));
+                     ip.getHostAddress(), rval));
             logEvent(IpReachabilityEvent.PROBE, rval);
         }
         mLastProbeTimeMs = SystemClock.elapsedRealtime();
@@ -378,22 +371,9 @@
         return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
     }
 
-    private static int getInterfaceIndex(String ifname) {
-        final NetworkInterface iface;
-        try {
-            iface = NetworkInterface.getByName(ifname);
-        } catch (SocketException e) {
-            throw new IllegalArgumentException("invalid interface '" + ifname + "': ", e);
-        }
-        if (iface == null) {
-            throw new IllegalArgumentException("NetworkInterface was null for " + ifname);
-        }
-        return iface.getIndex();
-    }
-
     private void logEvent(int probeType, int errorCode) {
         int eventType = probeType | (errorCode & 0xff);
-        mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType));
+        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
     }
 
     private void logNudFailed(ProvisioningChange delta) {
@@ -401,6 +381,6 @@
         boolean isFromProbe = (duration < getProbeWakeLockDuration());
         boolean isProvisioningLost = (delta == ProvisioningChange.LOST_PROVISIONING);
         int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost);
-        mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType));
+        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
     }
 }
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index cb3123c..49a1e79 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -25,6 +25,7 @@
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
 import android.net.TrafficStats;
+import android.net.util.InterfaceParams;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructGroupReq;
@@ -96,9 +97,7 @@
             (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
     };
 
-    private final String mIfName;
-    private final int mIfIndex;
-    private final byte[] mHwAddr;
+    private final InterfaceParams mInterface;
     private final InetSocketAddress mAllNodes;
 
     // This lock is to protect the RA from being updated while being
@@ -223,11 +222,9 @@
     }
 
 
-    public RouterAdvertisementDaemon(String ifname, int ifindex, byte[] hwaddr) {
-        mIfName = ifname;
-        mIfIndex = ifindex;
-        mHwAddr = hwaddr;
-        mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0);
+    public RouterAdvertisementDaemon(InterfaceParams ifParams) {
+        mInterface = ifParams;
+        mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
         mDeprecatedInfoTracker = new DeprecatedInfoTracker();
     }
 
@@ -279,7 +276,7 @@
 
         try {
             putHeader(ra, mRaParams != null && mRaParams.hasDefaultRoute);
-            putSlla(ra, mHwAddr);
+            putSlla(ra, mInterface.macAddr.toByteArray());
             mRaLength = ra.position();
 
             // https://tools.ietf.org/html/rfc5175#section-4 says:
@@ -579,9 +576,9 @@
             // Setting SNDTIMEO is purely for defensive purposes.
             Os.setsockoptTimeval(
                     mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(SEND_TIMEOUT_MS));
-            Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIfName);
+            Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mInterface.name);
             NetworkUtils.protectFromVpn(mSocket);
-            NetworkUtils.setupRaSocket(mSocket, mIfIndex);
+            NetworkUtils.setupRaSocket(mSocket, mInterface.index);
         } catch (ErrnoException | IOException e) {
             Log.e(TAG, "Failed to create RA daemon socket: " + e);
             return false;
@@ -614,7 +611,7 @@
         final InetAddress destip = dest.getAddress();
         return (destip instanceof Inet6Address) &&
                 destip.isLinkLocalAddress() &&
-               (((Inet6Address) destip).getScopeId() == mIfIndex);
+               (((Inet6Address) destip).getScopeId() == mInterface.index);
     }
 
     private void maybeSendRA(InetSocketAddress dest) {
diff --git a/services/net/java/android/net/util/ConnectivityPacketSummary.java b/services/net/java/android/net/util/ConnectivityPacketSummary.java
index dae93af..4951400 100644
--- a/services/net/java/android/net/util/ConnectivityPacketSummary.java
+++ b/services/net/java/android/net/util/ConnectivityPacketSummary.java
@@ -17,6 +17,7 @@
 package android.net.util;
 
 import android.net.dhcp.DhcpPacket;
+import android.net.MacAddress;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -45,21 +46,20 @@
     private final ByteBuffer mPacket;
     private final String mSummary;
 
-    public static String summarize(byte[] hwaddr, byte[] buffer) {
+    public static String summarize(MacAddress hwaddr, byte[] buffer) {
         return summarize(hwaddr, buffer, buffer.length);
     }
 
     // Methods called herein perform some but by no means all error checking.
     // They may throw runtime exceptions on malformed packets.
-    public static String summarize(byte[] hwaddr, byte[] buffer, int length) {
-        if ((hwaddr == null) || (hwaddr.length != ETHER_ADDR_LEN)) return null;
-        if (buffer == null) return null;
+    public static String summarize(MacAddress macAddr, byte[] buffer, int length) {
+        if ((macAddr == null) || (buffer == null)) return null;
         length = Math.min(length, buffer.length);
-        return (new ConnectivityPacketSummary(hwaddr, buffer, length)).toString();
+        return (new ConnectivityPacketSummary(macAddr, buffer, length)).toString();
     }
 
-    private ConnectivityPacketSummary(byte[] hwaddr, byte[] buffer, int length) {
-        mHwAddr = hwaddr;
+    private ConnectivityPacketSummary(MacAddress macAddr, byte[] buffer, int length) {
+        mHwAddr = macAddr.toByteArray();
         mBytes = buffer;
         mLength = Math.min(length, mBytes.length);
         mPacket = ByteBuffer.wrap(mBytes, 0, mLength);
diff --git a/services/net/java/android/net/util/InterfaceParams.java b/services/net/java/android/net/util/InterfaceParams.java
new file mode 100644
index 0000000..a4b2fbb
--- /dev/null
+++ b/services/net/java/android/net/util/InterfaceParams.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static android.net.MacAddress.ALL_ZEROS_ADDRESS;
+import static android.net.util.NetworkConstants.ETHER_MTU;
+import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.net.MacAddress;
+import android.text.TextUtils;
+
+import java.net.NetworkInterface;
+import java.net.SocketException;
+
+
+/**
+ * Encapsulate the interface parameters common to IpClient/IpServer components.
+ *
+ * Basically all java.net.NetworkInterface methods throw Exceptions. IpClient
+ * and IpServer (sub)components need most or all of this information at some
+ * point during their lifecycles, so pass only this simplified object around
+ * which can be created once when IpClient/IpServer are told to start.
+ *
+ * @hide
+ */
+public class InterfaceParams {
+    public final String name;
+    public final int index;
+    public final MacAddress macAddr;
+    public final int defaultMtu;
+
+    public static InterfaceParams getByName(String name) {
+        final NetworkInterface netif = getNetworkInterfaceByName(name);
+        if (netif == null) return null;
+
+        // Not all interfaces have MAC addresses, e.g. rmnet_data0.
+        final MacAddress macAddr = getMacAddress(netif);
+
+        try {
+            return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU());
+        } catch (IllegalArgumentException|SocketException e) {
+            return null;
+        }
+    }
+
+    public InterfaceParams(String name, int index, MacAddress macAddr) {
+        this(name, index, macAddr, ETHER_MTU);
+    }
+
+    public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) {
+        checkArgument((!TextUtils.isEmpty(name)), "impossible interface name");
+        checkArgument((index > 0), "invalid interface index");
+        this.name = name;
+        this.index = index;
+        this.macAddr = (macAddr != null) ? macAddr : ALL_ZEROS_ADDRESS;
+        this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu);
+    }
+
+    private static NetworkInterface getNetworkInterfaceByName(String name) {
+        try {
+            return NetworkInterface.getByName(name);
+        } catch (NullPointerException|SocketException e) {
+            return null;
+        }
+    }
+
+    private static MacAddress getMacAddress(NetworkInterface netif) {
+        try {
+            return MacAddress.fromBytes(netif.getHardwareAddress());
+        } catch (IllegalArgumentException|NullPointerException|SocketException e) {
+            return null;
+        }
+    }
+}
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 1ca6f26..ae311f8 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -49,7 +49,7 @@
 
 LOCAL_JAVA_LIBRARIES := \
     junit \
-    platform-robolectric-3.5.1-prebuilt
+    platform-robolectric-3.6.1-prebuilt
 
 LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
 LOCAL_MODULE := FrameworksServicesRoboTests
@@ -74,4 +74,4 @@
 
 LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java
 
-include prebuilts/misc/common/robolectric/3.5.1/run_robotests.mk
+include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index f9ebd28..dc0a4e3 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -16,7 +16,11 @@
 
 package com.android.server.backup;
 
-import static com.android.server.backup.testing.TransportTestUtils.TRANSPORT_NAMES;
+import static com.android.server.backup.testing.TransportData.backupTransport;
+import static com.android.server.backup.testing.TransportData.d2dTransport;
+import static com.android.server.backup.testing.TransportData.localTransport;
+import static com.android.server.backup.testing.TransportTestUtils.setUpCurrentTransport;
+import static com.android.server.backup.testing.TransportTestUtils.setUpTransports;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -24,6 +28,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
@@ -39,8 +44,10 @@
 import android.provider.Settings;
 
 import com.android.server.backup.testing.ShadowAppBackupUtils;
+import com.android.server.backup.testing.ShadowBackupPolicyEnforcer;
+import com.android.server.backup.testing.TransportData;
 import com.android.server.backup.testing.TransportTestUtils;
-import com.android.server.backup.testing.TransportTestUtils.TransportData;
+import com.android.server.backup.testing.TransportTestUtils.TransportMock;
 import com.android.server.backup.transport.TransportNotRegisteredException;
 import com.android.server.testing.FrameworkRobolectricTestRunner;
 import com.android.server.testing.SystemLoaderClasses;
@@ -57,38 +64,40 @@
 import org.robolectric.shadows.ShadowLog;
 import org.robolectric.shadows.ShadowLooper;
 import org.robolectric.shadows.ShadowSettings;
+import org.robolectric.shadows.ShadowSystemClock;
 
 import java.io.File;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 @RunWith(FrameworkRobolectricTestRunner.class)
 @Config(
     manifest = Config.NONE,
     sdk = 26,
-    shadows = {ShadowAppBackupUtils.class}
+    shadows = {ShadowAppBackupUtils.class, ShadowBackupPolicyEnforcer.class}
 )
 @SystemLoaderClasses({RefactoredBackupManagerService.class, TransportManager.class})
 @Presubmit
 public class BackupManagerServiceRoboTest {
     private static final String TAG = "BMSTest";
-    private static final String TRANSPORT_NAME =
-            "com.google.android.gms/.backup.BackupTransportService";
 
     @Mock private TransportManager mTransportManager;
     private HandlerThread mBackupThread;
     private ShadowLooper mShadowBackupLooper;
     private File mBaseStateDir;
     private File mDataDir;
-    private RefactoredBackupManagerService mBackupManagerService;
     private ShadowContextWrapper mShadowContext;
     private Context mContext;
+    private TransportData mTransport;
+    private String mTransportName;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mTransport = backupTransport();
+        mTransportName = mTransport.transportName;
+
         mBackupThread = new HandlerThread("backup-test");
         mBackupThread.setUncaughtExceptionHandler(
                 (t, e) -> ShadowLog.e(TAG, "Uncaught exception in test thread " + t.getName(), e));
@@ -103,20 +112,14 @@
         mBaseStateDir = new File(cacheDir, "base_state_dir");
         mDataDir = new File(cacheDir, "data_dir");
 
-        mBackupManagerService =
-                new RefactoredBackupManagerService(
-                        mContext,
-                        new Trampoline(mContext),
-                        mBackupThread,
-                        mBaseStateDir,
-                        mDataDir,
-                        mTransportManager);
+        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
     }
 
     @After
     public void tearDown() throws Exception {
         mBackupThread.quit();
         ShadowAppBackupUtils.reset();
+        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
     }
 
     /* Tests for destination string */
@@ -124,10 +127,12 @@
     @Test
     public void testDestinationString() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-        when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
+        when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
                 .thenReturn("destinationString");
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
-        String destination = mBackupManagerService.getDestinationString(TRANSPORT_NAME);
+        String destination = backupManagerService.getDestinationString(mTransportName);
 
         assertThat(destination).isEqualTo("destinationString");
     }
@@ -135,10 +140,12 @@
     @Test
     public void testDestinationString_whenTransportNotRegistered() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-        when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
+        when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
                 .thenThrow(TransportNotRegisteredException.class);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
-        String destination = mBackupManagerService.getDestinationString(TRANSPORT_NAME);
+        String destination = backupManagerService.getDestinationString(mTransportName);
 
         assertThat(destination).isNull();
     }
@@ -146,12 +153,14 @@
     @Test
     public void testDestinationString_withoutPermission() throws Exception {
         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
-        when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
+        when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
                 .thenThrow(TransportNotRegisteredException.class);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
         expectThrows(
                 SecurityException.class,
-                () -> mBackupManagerService.getDestinationString(TRANSPORT_NAME));
+                () -> backupManagerService.getDestinationString(mTransportName));
     }
 
     /* Tests for app eligibility */
@@ -159,24 +168,28 @@
     @Test
     public void testIsAppEligibleForBackup_whenAppEligible() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-        TransportData transport =
-                TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
+        TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport());
         ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> true;
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
-        boolean result = mBackupManagerService.isAppEligibleForBackup("app.package");
+        boolean result = backupManagerService.isAppEligibleForBackup("app.package");
 
         assertThat(result).isTrue();
+
         verify(mTransportManager)
-                .disposeOfTransportClient(eq(transport.transportClientMock), any());
+                .disposeOfTransportClient(eq(transportMock.transportClient), any());
     }
 
     @Test
     public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-        TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
+        setUpCurrentTransport(mTransportManager, mTransport);
         ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false;
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
-        boolean result = mBackupManagerService.isAppEligibleForBackup("app.package");
+        boolean result = backupManagerService.isAppEligibleForBackup("app.package");
 
         assertThat(result).isFalse();
     }
@@ -184,38 +197,43 @@
     @Test
     public void testIsAppEligibleForBackup_withoutPermission() throws Exception {
         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
-        TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
+        setUpCurrentTransport(mTransportManager, mTransport);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
         expectThrows(
                 SecurityException.class,
-                () -> mBackupManagerService.isAppEligibleForBackup("app.package"));
+                () -> backupManagerService.isAppEligibleForBackup("app.package"));
     }
 
     @Test
     public void testFilterAppsEligibleForBackup() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-        TransportData transport =
-                TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
+        TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport);
         Map<String, Boolean> packagesMap = new HashMap<>();
         packagesMap.put("package.a", true);
         packagesMap.put("package.b", false);
         ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = packagesMap::get;
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
         String[] packages = packagesMap.keySet().toArray(new String[packagesMap.size()]);
 
-        String[] filtered = mBackupManagerService.filterAppsEligibleForBackup(packages);
+        String[] filtered = backupManagerService.filterAppsEligibleForBackup(packages);
 
         assertThat(filtered).asList().containsExactly("package.a");
         verify(mTransportManager)
-                .disposeOfTransportClient(eq(transport.transportClientMock), any());
+                .disposeOfTransportClient(eq(transportMock.transportClient), any());
     }
 
     @Test
     public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false;
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
         String[] filtered =
-                mBackupManagerService.filterAppsEligibleForBackup(
+                backupManagerService.filterAppsEligibleForBackup(
                         new String[] {"package.a", "package.b"});
 
         assertThat(filtered).isEmpty();
@@ -224,12 +242,14 @@
     @Test
     public void testFilterAppsEligibleForBackup_withoutPermission() throws Exception {
         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
-        TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
+        setUpCurrentTransport(mTransportManager, mTransport);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
         expectThrows(
                 SecurityException.class,
                 () ->
-                        mBackupManagerService.filterAppsEligibleForBackup(
+                        backupManagerService.filterAppsEligibleForBackup(
                                 new String[] {"package.a", "package.b"}));
     }
 
@@ -238,14 +258,14 @@
     private TransportData mNewTransport;
     private TransportData mOldTransport;
     private ComponentName mNewTransportComponent;
-    private ISelectBackupTransportCallback mCallback;
+    private ComponentName mOldTransportComponent;
 
     private void setUpForSelectTransport() throws Exception {
-        List<TransportData> transports =
-                TransportTestUtils.setUpTransports(mTransportManager, TRANSPORT_NAMES);
-        mNewTransport = transports.get(0);
-        mNewTransportComponent = mNewTransport.transportClientMock.getTransportComponent();
-        mOldTransport = transports.get(1);
+        mNewTransport = backupTransport();
+        mNewTransportComponent = mNewTransport.getTransportComponent();
+        mOldTransport = d2dTransport();
+        mOldTransportComponent = mOldTransport.getTransportComponent();
+        setUpTransports(mTransportManager, mNewTransport, mOldTransport, localTransport());
         when(mTransportManager.selectTransport(eq(mNewTransport.transportName)))
                 .thenReturn(mOldTransport.transportName);
     }
@@ -254,9 +274,11 @@
     public void testSelectBackupTransport() throws Exception {
         setUpForSelectTransport();
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
         String oldTransport =
-                mBackupManagerService.selectBackupTransport(mNewTransport.transportName);
+                backupManagerService.selectBackupTransport(mNewTransport.transportName);
 
         assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
         assertThat(oldTransport).isEqualTo(mOldTransport.transportName);
@@ -266,10 +288,12 @@
     public void testSelectBackupTransport_withoutPermission() throws Exception {
         setUpForSelectTransport();
         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
 
         expectThrows(
                 SecurityException.class,
-                () -> mBackupManagerService.selectBackupTransport(mNewTransport.transportName));
+                () -> backupManagerService.selectBackupTransport(mNewTransport.transportName));
     }
 
     @Test
@@ -278,9 +302,11 @@
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
                 .thenReturn(BackupManager.SUCCESS);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
 
-        mBackupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
+        backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
 
         mShadowBackupLooper.runToEndOfTasks();
         assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
@@ -288,14 +314,53 @@
     }
 
     @Test
+    public void testSelectBackupTransportAsync_whenMandatoryTransport() throws Exception {
+        setUpForSelectTransport();
+        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(mNewTransportComponent);
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
+                .thenReturn(BackupManager.SUCCESS);
+        ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
+
+        backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
+
+        mShadowBackupLooper.runToEndOfTasks();
+        assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
+        verify(callback).onSuccess(eq(mNewTransport.transportName));
+    }
+
+    @Test
+    public void testSelectBackupTransportAsync_whenOtherThanMandatoryTransport()
+            throws Exception {
+        setUpForSelectTransport();
+        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(mOldTransportComponent);
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
+                .thenReturn(BackupManager.SUCCESS);
+        ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
+
+        backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
+
+        mShadowBackupLooper.runToEndOfTasks();
+        assertThat(getSettingsTransport()).isNotEqualTo(mNewTransport.transportName);
+        verify(callback).onFailure(eq(BackupManager.ERROR_BACKUP_NOT_ALLOWED));
+    }
+
+    @Test
     public void testSelectBackupTransportAsync_whenRegistrationFails() throws Exception {
         setUpForSelectTransport();
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
                 .thenReturn(BackupManager.ERROR_TRANSPORT_UNAVAILABLE);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
 
-        mBackupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
+        backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
 
         mShadowBackupLooper.runToEndOfTasks();
         assertThat(getSettingsTransport()).isNotEqualTo(mNewTransport.transportName);
@@ -304,19 +369,19 @@
 
     @Test
     public void testSelectBackupTransportAsync_whenTransportGetsUnregistered() throws Exception {
-        TransportTestUtils.setUpTransports(
-                mTransportManager, new TransportData(TRANSPORT_NAME, null, null));
-        ComponentName newTransportComponent =
-                TransportTestUtils.transportComponentName(TRANSPORT_NAME);
+        setUpTransports(mTransportManager, mTransport.unregistered());
+        ComponentName newTransportComponent = mTransport.getTransportComponent();
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         when(mTransportManager.registerAndSelectTransport(eq(newTransportComponent)))
                 .thenReturn(BackupManager.SUCCESS);
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
 
-        mBackupManagerService.selectBackupTransportAsync(newTransportComponent, callback);
+        backupManagerService.selectBackupTransportAsync(newTransportComponent, callback);
 
         mShadowBackupLooper.runToEndOfTasks();
-        assertThat(getSettingsTransport()).isNotEqualTo(TRANSPORT_NAME);
+        assertThat(getSettingsTransport()).isNotEqualTo(mTransportName);
         verify(callback).onFailure(anyInt());
     }
 
@@ -324,13 +389,14 @@
     public void testSelectBackupTransportAsync_withoutPermission() throws Exception {
         setUpForSelectTransport();
         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
-        ComponentName newTransportComponent =
-                mNewTransport.transportClientMock.getTransportComponent();
+        RefactoredBackupManagerService backupManagerService =
+                createInitializedBackupManagerService();
+        ComponentName newTransportComponent = mNewTransport.getTransportComponent();
 
         expectThrows(
                 SecurityException.class,
                 () ->
-                        mBackupManagerService.selectBackupTransportAsync(
+                        backupManagerService.selectBackupTransportAsync(
                                 newTransportComponent, mock(ISelectBackupTransportCallback.class)));
     }
 
@@ -338,4 +404,55 @@
         return ShadowSettings.ShadowSecure.getString(
                 mContext.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
     }
+
+    /* Miscellaneous tests */
+
+    @Test
+    public void testConstructor_postRegisterTransports() {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+
+        createBackupManagerService();
+
+        mShadowBackupLooper.runToEndOfTasks();
+        verify(mTransportManager).registerTransports();
+    }
+
+    @Test
+    public void testConstructor_doesNotRegisterTransportsSynchronously() {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+
+        createBackupManagerService();
+
+        // Operations posted to mBackupThread only run with mShadowBackupLooper.runToEndOfTasks()
+        verify(mTransportManager, never()).registerTransports();
+    }
+
+    private RefactoredBackupManagerService createBackupManagerService() {
+        return new RefactoredBackupManagerService(
+                mContext,
+                new Trampoline(mContext),
+                mBackupThread,
+                mBaseStateDir,
+                mDataDir,
+                mTransportManager);
+    }
+
+    private RefactoredBackupManagerService createInitializedBackupManagerService() {
+        RefactoredBackupManagerService backupManagerService =
+                new RefactoredBackupManagerService(
+                        mContext,
+                        new Trampoline(mContext),
+                        mBackupThread,
+                        mBaseStateDir,
+                        mDataDir,
+                        mTransportManager);
+        mShadowBackupLooper.runToEndOfTasks();
+        // Handler instances have their own clock, so advancing looper (with runToEndOfTasks())
+        // above does NOT advance the handlers' clock, hence whenever a handler post messages with
+        // specific time to the looper the time of those messages will be before the looper's time.
+        // To fix this we advance SystemClock as well since that is from where the handlers read
+        // time.
+        ShadowSystemClock.setCurrentTimeMillis(mShadowBackupLooper.getScheduler().getCurrentTime());
+        return backupManagerService;
+    }
 }
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index acd670f..cf0bc23 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -16,108 +16,97 @@
 
 package com.android.server.backup;
 
+import static com.android.server.backup.testing.TransportData.genericTransport;
+import static com.android.server.backup.testing.TransportTestUtils.mockTransport;
+import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
+
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.mock;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.shadow.api.Shadow.extract;
 import static org.testng.Assert.expectThrows;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+
 import android.annotation.Nullable;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.os.IBinder;
-import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
-import com.android.internal.backup.IBackupTransport;
-import com.android.server.backup.testing.ShadowBackupTransportStub;
 import com.android.server.backup.testing.ShadowContextImplForBackup;
-import com.android.server.backup.testing.ShadowPackageManagerForBackup;
-import com.android.server.backup.testing.TransportBoundListenerStub;
+import com.android.server.testing.shadows.FrameworkShadowPackageManager;
+import com.android.server.backup.testing.TransportData;
+import com.android.server.backup.testing.TransportTestUtils.TransportMock;
+import com.android.server.backup.transport.OnTransportRegisteredListener;
 import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.transport.TransportClientManager;
 import com.android.server.backup.transport.TransportNotRegisteredException;
 import com.android.server.testing.FrameworkRobolectricTestRunner;
 import com.android.server.testing.SystemLoaderClasses;
+import com.android.server.testing.shadows.FrameworkShadowContextImpl;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLog;
-import org.robolectric.shadows.ShadowLooper;
 import org.robolectric.shadows.ShadowPackageManager;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
 
 @RunWith(FrameworkRobolectricTestRunner.class)
 @Config(
-        manifest = Config.NONE,
-        sdk = 26,
-        shadows = {
-                ShadowContextImplForBackup.class,
-                ShadowBackupTransportStub.class,
-                ShadowPackageManagerForBackup.class
-        }
+    manifest = Config.NONE,
+    sdk = 26,
+    shadows = {FrameworkShadowPackageManager.class, FrameworkShadowContextImpl.class}
 )
 @SystemLoaderClasses({TransportManager.class})
 @Presubmit
 public class TransportManagerTest {
-    private static final String PACKAGE_NAME = "some.package.name";
-    private static final String ANOTHER_PACKAGE_NAME = "another.package.name";
+    private static final String PACKAGE_A = "some.package.a";
+    private static final String PACKAGE_B = "some.package.b";
 
-    private TransportInfo mTransport1;
-    private TransportInfo mTransport2;
+    @Mock private OnTransportRegisteredListener mListener;
+    @Mock private TransportClientManager mTransportClientManager;
+    private TransportData mTransportA1;
+    private TransportData mTransportA2;
+    private TransportData mTransportB1;
 
-    private ShadowPackageManager mPackageManagerShadow;
-
-    private final TransportBoundListenerStub mTransportBoundListenerStub =
-            new TransportBoundListenerStub(true);
+    private ShadowPackageManager mShadowPackageManager;
+    private Context mContext;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        ShadowLog.stream = System.out;
-
-        mPackageManagerShadow =
-                (ShadowPackageManagerForBackup)
+        mShadowPackageManager =
+                (FrameworkShadowPackageManager)
                         extract(RuntimeEnvironment.application.getPackageManager());
+        mContext = RuntimeEnvironment.application.getApplicationContext();
 
-        mTransport1 = new TransportInfo(
-                PACKAGE_NAME,
-                "transport1.name",
-                new Intent(),
-                "currentDestinationString",
-                new Intent(),
-                "dataManagementLabel");
-        mTransport2 = new TransportInfo(
-                PACKAGE_NAME,
-                "transport2.name",
-                new Intent(),
-                "currentDestinationString",
-                new Intent(),
-                "dataManagementLabel");
-
-        ShadowContextImplForBackup.sComponentBinderMap.put(mTransport1.componentName,
-                mTransport1.binder);
-        ShadowContextImplForBackup.sComponentBinderMap.put(mTransport2.componentName,
-                mTransport2.binder);
-        ShadowBackupTransportStub.sBinderTransportMap.put(
-                mTransport1.binder, mTransport1.binderInterface);
-        ShadowBackupTransportStub.sBinderTransportMap.put(
-                mTransport2.binder, mTransport2.binderInterface);
+        mTransportA1 = genericTransport(PACKAGE_A, "TransportFoo");
+        mTransportA2 = genericTransport(PACKAGE_A, "TransportBar");
+        mTransportB1 = genericTransport(PACKAGE_B, "TransportBaz");
     }
 
     @After
@@ -126,560 +115,441 @@
     }
 
     @Test
-    public void onPackageAdded_bindsToAllTransports() throws Exception {
-        setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
-                ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
-
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                new HashSet<>(Arrays.asList(
-                        mTransport1.componentName, mTransport2.componentName)),
-                null /* defaultTransport */,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
-        transportManager.onPackageAdded(PACKAGE_NAME);
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.componentName, mTransport2.componentName));
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.name, mTransport2.name));
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
-                .isTrue();
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
-                .isTrue();
-    }
-
-    @Test
-    public void onPackageAdded_oneTransportUnavailable_bindsToOnlyOneTransport() throws Exception {
-        setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
-                ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
-
-        ShadowContextImplForBackup.sUnbindableComponents.add(mTransport1.componentName);
-
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                new HashSet<>(Arrays.asList(
-                        mTransport1.componentName, mTransport2.componentName)),
-                null /* defaultTransport */,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
-        transportManager.onPackageAdded(PACKAGE_NAME);
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                Collections.singleton(mTransport2.componentName));
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                Collections.singleton(mTransport2.name));
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
-                .isFalse();
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
-                .isTrue();
-    }
-
-    @Test
-    public void onPackageAdded_whitelistIsNull_doesNotBindToTransports() throws Exception {
-        setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
-                ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
-
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                null /* whitelist */,
-                null /* defaultTransport */,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
-        transportManager.onPackageAdded(PACKAGE_NAME);
-
-        assertThat(transportManager.getAllTransportComponents()).isEmpty();
-        assertThat(transportManager.getBoundTransportNames()).isEmpty();
-        assertThat(mTransportBoundListenerStub.isCalled()).isFalse();
-    }
-
-    @Test
-    public void onPackageAdded_onlyOneTransportWhitelisted_onlyConnectsToWhitelistedTransport()
-            throws Exception {
-        setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
-                ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
-
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                new HashSet<>(Collections.singleton(mTransport2.componentName)),
-                null /* defaultTransport */,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
-        transportManager.onPackageAdded(PACKAGE_NAME);
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                Collections.singleton(mTransport2.componentName));
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                Collections.singleton(mTransport2.name));
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
-                .isFalse();
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
-                .isTrue();
-    }
-
-    @Test
-    public void onPackageAdded_appIsNotPrivileged_doesNotBindToTransports() throws Exception {
-        setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2), 0);
-
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                new HashSet<>(Arrays.asList(
-                        mTransport1.componentName, mTransport2.componentName)),
-                null /* defaultTransport */,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
-        transportManager.onPackageAdded(PACKAGE_NAME);
-
-        assertThat(transportManager.getAllTransportComponents()).isEmpty();
-        assertThat(transportManager.getBoundTransportNames()).isEmpty();
-        assertThat(mTransportBoundListenerStub.isCalled()).isFalse();
-    }
-
-    @Test
-    public void onPackageRemoved_transportsUnbound() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        transportManager.onPackageRemoved(PACKAGE_NAME);
-
-        assertThat(transportManager.getAllTransportComponents()).isEmpty();
-        assertThat(transportManager.getBoundTransportNames()).isEmpty();
-    }
-
-    @Test
-    public void onPackageRemoved_incorrectPackageName_nothingHappens() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        transportManager.onPackageRemoved(ANOTHER_PACKAGE_NAME);
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.componentName, mTransport2.componentName));
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.name, mTransport2.name));
-    }
-
-    @Test
-    public void onPackageChanged_oneComponentChanged_onlyOneTransportRebound() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        transportManager.onPackageChanged(PACKAGE_NAME, new String[]{mTransport2.name});
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.componentName, mTransport2.componentName));
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.name, mTransport2.name));
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
-                .isFalse();
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
-                .isTrue();
-    }
-
-    @Test
-    public void onPackageChanged_nothingChanged_noTransportsRebound() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        transportManager.onPackageChanged(PACKAGE_NAME, new String[0]);
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.componentName, mTransport2.componentName));
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.name, mTransport2.name));
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
-                .isFalse();
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
-                .isFalse();
-    }
-
-    @Test
-    public void onPackageChanged_unexpectedComponentChanged_noTransportsRebound() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        transportManager.onPackageChanged(PACKAGE_NAME, new String[]{"unexpected.component"});
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.componentName, mTransport2.componentName));
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.name, mTransport2.name));
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
-                .isFalse();
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
-                .isFalse();
-    }
-
-    @Test
-    public void onPackageChanged_transportsRebound() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        transportManager.onPackageChanged(PACKAGE_NAME, new String[]{mTransport2.name});
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.componentName, mTransport2.componentName));
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                Arrays.asList(mTransport1.name, mTransport2.name));
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
-                .isFalse();
-        assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
-                .isTrue();
-    }
-
-    @Test
-    public void getTransportBinder_returnsCorrectBinder() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        assertThat(transportManager.getTransportBinder(mTransport1.name)).isEqualTo(
-                mTransport1.binderInterface);
-        assertThat(transportManager.getTransportBinder(mTransport2.name)).isEqualTo(
-                mTransport2.binderInterface);
-    }
-
-    @Test
-    public void getTransportBinder_incorrectTransportName_returnsNull() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        assertThat(transportManager.getTransportBinder("incorrect.transport")).isNull();
-    }
-
-    @Test
-    public void getTransportBinder_oneTransportUnavailable_returnsCorrectBinder() throws Exception {
+    public void testRegisterTransports() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpPackage(PACKAGE_B, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2, mTransportB1);
         TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(Collections.singletonList(mTransport2),
-                        Collections.singletonList(mTransport1), mTransport1.name);
+                createTransportManager(mTransportA1, mTransportA2, mTransportB1);
 
-        assertThat(transportManager.getTransportBinder(mTransport1.name)).isNull();
-        assertThat(transportManager.getTransportBinder(mTransport2.name)).isEqualTo(
-                mTransport2.binderInterface);
+        transportManager.registerTransports();
+
+        assertRegisteredTransports(
+                transportManager, asList(mTransportA1, mTransportA2, mTransportB1));
+
+        verify(mListener)
+                .onTransportRegistered(mTransportA1.transportName, mTransportA1.transportDirName);
+        verify(mListener)
+                .onTransportRegistered(mTransportA2.transportName, mTransportA2.transportDirName);
+        verify(mListener)
+                .onTransportRegistered(mTransportB1.transportName, mTransportB1.transportDirName);
     }
 
     @Test
-    public void getCurrentTransport_selectTransportNotCalled_returnsDefaultTransport()
+    public void
+            testRegisterTransports_whenOneTransportUnavailable_doesNotRegisterUnavailableTransport()
+                    throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        TransportData transport1 = mTransportA1.unavailable();
+        TransportData transport2 = mTransportA2;
+        setUpTransports(transport1, transport2);
+        TransportManager transportManager = createTransportManager(transport1, transport2);
+
+        transportManager.registerTransports();
+
+        assertRegisteredTransports(transportManager, singletonList(transport2));
+        verify(mListener, never())
+                .onTransportRegistered(transport1.transportName, transport1.transportDirName);
+        verify(mListener)
+                .onTransportRegistered(transport2.transportName, transport2.transportDirName);
+    }
+
+    @Test
+    public void testRegisterTransports_whenWhitelistIsEmpty_doesNotRegisterTransports()
             throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(null);
 
-        assertThat(transportManager.getCurrentTransportName()).isEqualTo(mTransport1.name);
+        transportManager.registerTransports();
+
+        assertRegisteredTransports(transportManager, emptyList());
+        verify(mListener, never()).onTransportRegistered(any(), any());
     }
 
     @Test
-    public void getCurrentTransport_selectTransportCalled_returnsCorrectTransport()
+    public void
+            testRegisterTransports_whenOnlyOneTransportWhitelisted_onlyRegistersWhitelistedTransport()
+                    throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(null, mTransportA1);
+
+        transportManager.registerTransports();
+
+        assertRegisteredTransports(transportManager, singletonList(mTransportA1));
+        verify(mListener)
+                .onTransportRegistered(mTransportA1.transportName, mTransportA1.transportDirName);
+        verify(mListener, never())
+                .onTransportRegistered(mTransportA2.transportName, mTransportA2.transportDirName);
+    }
+
+    @Test
+    public void testRegisterTransports_whenAppIsNotPrivileged_doesNotRegisterTransports()
             throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        assertThat(transportManager.getCurrentTransportName()).isEqualTo(mTransport1.name);
-
-        transportManager.selectTransport(mTransport2.name);
-
-        assertThat(transportManager.getCurrentTransportName()).isEqualTo(mTransport2.name);
-    }
-
-    @Test
-    public void getCurrentTransportBinder_returnsCorrectBinder() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
-
-        assertThat(transportManager.getCurrentTransportBinder())
-                .isEqualTo(mTransport1.binderInterface);
-    }
-
-    @Test
-    public void getCurrentTransportBinder_transportNotBound_returnsNull() throws Exception {
+        // Note ApplicationInfo.PRIVATE_FLAG_PRIVILEGED is missing from flags
+        setUpPackage(PACKAGE_A, 0);
+        setUpTransports(mTransportA1, mTransportA2);
         TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(Collections.singletonList(mTransport2),
-                        Collections.singletonList(mTransport1), mTransport2.name);
+                createTransportManager(null, mTransportA1, mTransportA2);
 
-        transportManager.selectTransport(mTransport1.name);
+        transportManager.registerTransports();
 
-        assertThat(transportManager.getCurrentTransportBinder()).isNull();
+        assertRegisteredTransports(transportManager, emptyList());
+        verify(mListener, never()).onTransportRegistered(any(), any());
     }
 
     @Test
-    public void getTransportName_returnsCorrectTransportName() throws Exception {
-        TransportManager transportManager = createTransportManagerAndSetUpTransports(
-                Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+    public void testOnPackageAdded_registerTransports() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1);
+        TransportManager transportManager = createTransportManager(mTransportA1);
 
-        assertThat(transportManager.getTransportName(mTransport1.binderInterface))
-                .isEqualTo(mTransport1.name);
-        assertThat(transportManager.getTransportName(mTransport2.binderInterface))
-                .isEqualTo(mTransport2.name);
+        transportManager.onPackageAdded(PACKAGE_A);
+
+        assertRegisteredTransports(transportManager, asList(mTransportA1));
+        verify(mListener)
+                .onTransportRegistered(mTransportA1.transportName, mTransportA1.transportDirName);
     }
 
     @Test
-    public void getTransportName_transportNotBound_returnsNull() throws Exception {
-        TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(Collections.singletonList(mTransport2),
-                        Collections.singletonList(mTransport1), mTransport1.name);
+    public void testOnPackageRemoved_unregisterTransports() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpPackage(PACKAGE_B, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportB1);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportB1);
+        transportManager.registerTransports();
 
-        assertThat(transportManager.getTransportName(mTransport1.binderInterface)).isNull();
-        assertThat(transportManager.getTransportName(mTransport2.binderInterface))
-                .isEqualTo(mTransport2.name);
+        transportManager.onPackageRemoved(PACKAGE_A);
+
+        assertRegisteredTransports(transportManager, singletonList(mTransportB1));
     }
 
     @Test
-    public void getTransportWhitelist_returnsCorrectWhiteList() throws Exception {
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                new HashSet<>(Arrays.asList(mTransport1.componentName, mTransport2.componentName)),
-                mTransport1.name,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
+    public void testOnPackageRemoved_whenUnknownPackage_nothingHappens() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1);
+        TransportManager transportManager = createTransportManager(mTransportA1);
+        transportManager.registerTransports();
 
-        assertThat(transportManager.getTransportWhitelist()).containsExactlyElementsIn(
-                Arrays.asList(mTransport1.componentName, mTransport2.componentName));
+        transportManager.onPackageRemoved(PACKAGE_A + "unknown");
+
+        assertRegisteredTransports(transportManager, singletonList(mTransportA1));
     }
 
     @Test
-    public void getTransportWhitelist_whiteListIsNull_returnsEmptyArray() throws Exception {
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                null /* whitelist */,
-                mTransport1.name,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
-
-        assertThat(transportManager.getTransportWhitelist()).isEmpty();
-    }
-
-    @Test
-    public void selectTransport_setsTransportCorrectlyAndReturnsPreviousTransport()
+    public void testOnPackageChanged_whenOneComponentChanged_onlyOneTransportReRegistered()
             throws Exception {
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                null /* whitelist */,
-                mTransport1.name,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
+        // Reset listener to verify calls after registerTransports() above
+        reset(mListener);
 
-        assertThat(transportManager.selectTransport(mTransport2.name)).isEqualTo(mTransport1.name);
-        assertThat(transportManager.selectTransport(mTransport1.name)).isEqualTo(mTransport2.name);
+        transportManager.onPackageChanged(
+                PACKAGE_A, mTransportA1.getTransportComponent().getClassName());
+
+        assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportA2));
+        verify(mListener)
+                .onTransportRegistered(mTransportA1.transportName, mTransportA1.transportDirName);
+        verify(mListener, never())
+                .onTransportRegistered(mTransportA2.transportName, mTransportA2.transportDirName);
     }
 
     @Test
-    public void getTransportClient_forRegisteredTransport_returnCorrectly() throws Exception {
+    public void testOnPackageChanged_whenNoComponentsChanged_doesNotRegisterTransports()
+            throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1);
+        TransportManager transportManager = createTransportManager(mTransportA1);
+        transportManager.registerTransports();
+        reset(mListener);
+
+        transportManager.onPackageChanged(PACKAGE_A);
+
+        assertRegisteredTransports(transportManager, singletonList(mTransportA1));
+        verify(mListener, never()).onTransportRegistered(any(), any());
+    }
+
+    @Test
+    public void testOnPackageChanged_whenUnknownComponentChanged_noTransportsRegistered()
+            throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1);
+        TransportManager transportManager = createTransportManager(mTransportA1);
+        transportManager.registerTransports();
+        reset(mListener);
+
+        transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A + ".UnknownComponent");
+
+        assertRegisteredTransports(transportManager, singletonList(mTransportA1));
+        verify(mListener, never()).onTransportRegistered(any(), any());
+    }
+
+    @Test
+    public void testOnPackageChanged_reRegisterTransports() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
+        reset(mListener);
+
+        transportManager.onPackageChanged(
+                PACKAGE_A,
+                mTransportA1.getTransportComponent().getClassName(),
+                mTransportA2.getTransportComponent().getClassName());
+
+        assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportA2));
+        verify(mListener)
+                .onTransportRegistered(mTransportA1.transportName, mTransportA1.transportDirName);
+        verify(mListener)
+                .onTransportRegistered(mTransportA2.transportName, mTransportA2.transportDirName);
+    }
+
+    @Test
+    public void testGetCurrentTransportName_whenSelectTransportNotCalled_returnsDefaultTransport()
+            throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
+
+        String currentTransportName = transportManager.getCurrentTransportName();
+
+        assertThat(currentTransportName).isEqualTo(mTransportA1.transportName);
+    }
+
+    @Test
+    public void testGetCurrentTransport_whenSelectTransportCalled_returnsSelectedTransport()
+            throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
+        transportManager.selectTransport(mTransportA2.transportName);
+
+        String currentTransportName = transportManager.getCurrentTransportName();
+
+        assertThat(currentTransportName).isEqualTo(mTransportA2.transportName);
+    }
+
+    @Test
+    public void testGetTransportWhitelist() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+
+        Set<ComponentName> transportWhitelist = transportManager.getTransportWhitelist();
+
+        assertThat(transportWhitelist)
+                .containsExactlyElementsIn(
+                        asList(
+                                mTransportA1.getTransportComponent(),
+                                mTransportA2.getTransportComponent()));
+    }
+
+    @Test
+    public void testSelectTransport() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
         TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(
-                        Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+                createTransportManager(null, mTransportA1, mTransportA2);
+
+        String transport1 = transportManager.selectTransport(mTransportA1.transportName);
+        String transport2 = transportManager.selectTransport(mTransportA2.transportName);
+
+        assertThat(transport1).isNull();
+        assertThat(transport2).isEqualTo(mTransportA1.transportName);
+    }
+
+    @Test
+    public void testGetTransportClient_forRegisteredTransport() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
 
         TransportClient transportClient =
-                transportManager.getTransportClient(mTransport1.name, "caller");
+                transportManager.getTransportClient(mTransportA1.transportName, "caller");
 
-        assertThat(transportClient.getTransportComponent()).isEqualTo(mTransport1.componentName);
+        assertThat(transportClient.getTransportComponent())
+                .isEqualTo(mTransportA1.getTransportComponent());
     }
 
     @Test
-    public void getTransportClient_forOldNameOfTransportThatChangedName_returnsNull()
+    public void testGetTransportClient_forOldNameOfTransportThatChangedName_returnsNull()
             throws Exception {
-        TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(
-                        Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
         transportManager.updateTransportAttributes(
-                mTransport1.componentName, "newName", null, "destinationString", null, null);
+                mTransportA1.getTransportComponent(),
+                "newName",
+                null,
+                "destinationString",
+                null,
+                null);
 
         TransportClient transportClient =
-                transportManager.getTransportClient(mTransport1.name, "caller");
+                transportManager.getTransportClient(mTransportA1.transportName, "caller");
 
         assertThat(transportClient).isNull();
     }
 
     @Test
-    public void getTransportClient_forNewNameOfTransportThatChangedName_returnsCorrectly()
+    public void testGetTransportClient_forNewNameOfTransportThatChangedName_returnsCorrectly()
             throws Exception {
-        TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(
-                        Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
         transportManager.updateTransportAttributes(
-                mTransport1.componentName, "newName", null, "destinationString", null, null);
+                mTransportA1.getTransportComponent(),
+                "newName",
+                null,
+                "destinationString",
+                null,
+                null);
 
-        TransportClient transportClient =
-                transportManager.getTransportClient("newName", "caller");
+        TransportClient transportClient = transportManager.getTransportClient("newName", "caller");
 
-        assertThat(transportClient.getTransportComponent()).isEqualTo(mTransport1.componentName);
+        assertThat(transportClient.getTransportComponent())
+                .isEqualTo(mTransportA1.getTransportComponent());
     }
 
     @Test
-    public void getTransportName_forTransportThatChangedName_returnsNewName()
-            throws Exception {
-        TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(
-                        Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+    public void testGetTransportName_forTransportThatChangedName_returnsNewName() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1, mTransportA2);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
         transportManager.updateTransportAttributes(
-                mTransport1.componentName, "newName", null, "destinationString", null, null);
+                mTransportA1.getTransportComponent(),
+                "newName",
+                null,
+                "destinationString",
+                null,
+                null);
 
-        String transportName = transportManager.getTransportName(mTransport1.componentName);
+        String transportName =
+                transportManager.getTransportName(mTransportA1.getTransportComponent());
 
         assertThat(transportName).isEqualTo("newName");
     }
 
     @Test
-    public void isTransportRegistered_returnsCorrectly() throws Exception {
-        TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(
-                        Collections.singletonList(mTransport1),
-                        Collections.singletonList(mTransport2),
-                        mTransport1.name);
+    public void testIsTransportRegistered() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1);
+        TransportManager transportManager = createTransportManager(mTransportA1, mTransportA2);
+        transportManager.registerTransports();
 
-        assertThat(transportManager.isTransportRegistered(mTransport1.name)).isTrue();
-        assertThat(transportManager.isTransportRegistered(mTransport2.name)).isFalse();
+        boolean isTransportA1Registered =
+                transportManager.isTransportRegistered(mTransportA1.transportName);
+        boolean isTransportA2Registered =
+                transportManager.isTransportRegistered(mTransportA2.transportName);
+
+        assertThat(isTransportA1Registered).isTrue();
+        assertThat(isTransportA2Registered).isFalse();
     }
 
     @Test
-    public void getTransportAttributes_forRegisteredTransport_returnsCorrectValues()
+    public void testGetTransportAttributes_forRegisteredTransport_returnsCorrectValues()
             throws Exception {
-        TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(
-                        Collections.singletonList(mTransport1),
-                        mTransport1.name);
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1);
+        TransportManager transportManager = createTransportManager(mTransportA1);
+        transportManager.registerTransports();
 
-        assertThat(transportManager.getTransportConfigurationIntent(mTransport1.name))
-                .isEqualTo(mTransport1.binderInterface.configurationIntent());
-        assertThat(transportManager.getTransportDataManagementIntent(mTransport1.name))
-                .isEqualTo(mTransport1.binderInterface.dataManagementIntent());
-        assertThat(transportManager.getTransportDataManagementLabel(mTransport1.name))
-                .isEqualTo(mTransport1.binderInterface.dataManagementLabel());
-        assertThat(transportManager.getTransportDirName(mTransport1.name))
-                .isEqualTo(mTransport1.binderInterface.transportDirName());
+        Intent configurationIntent =
+                transportManager.getTransportConfigurationIntent(mTransportA1.transportName);
+        Intent dataManagementIntent =
+                transportManager.getTransportDataManagementIntent(mTransportA1.transportName);
+        String dataManagementLabel =
+                transportManager.getTransportDataManagementLabel(mTransportA1.transportName);
+        String transportDirName = transportManager.getTransportDirName(mTransportA1.transportName);
+
+        assertThat(configurationIntent).isEqualTo(mTransportA1.configurationIntent);
+        assertThat(dataManagementIntent).isEqualTo(mTransportA1.dataManagementIntent);
+        assertThat(dataManagementLabel).isEqualTo(mTransportA1.dataManagementLabel);
+        assertThat(transportDirName).isEqualTo(mTransportA1.transportDirName);
     }
 
     @Test
-    public void getTransportAttributes_forUnregisteredTransport_throws()
-            throws Exception {
-        TransportManager transportManager =
-                createTransportManagerAndSetUpTransports(
-                        Collections.singletonList(mTransport1),
-                        Collections.singletonList(mTransport2),
-                        mTransport1.name);
+    public void testGetTransportAttributes_forUnregisteredTransport_throws() throws Exception {
+        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        setUpTransports(mTransportA1);
+        TransportManager transportManager = createTransportManager(mTransportA1);
+        transportManager.registerTransports();
 
         expectThrows(
                 TransportNotRegisteredException.class,
-                () -> transportManager.getTransportConfigurationIntent(mTransport2.name));
+                () -> transportManager.getTransportConfigurationIntent(mTransportA2.transportName));
         expectThrows(
                 TransportNotRegisteredException.class,
-                () -> transportManager.getTransportDataManagementIntent(
-                        mTransport2.name));
+                () ->
+                        transportManager.getTransportDataManagementIntent(
+                                mTransportA2.transportName));
         expectThrows(
                 TransportNotRegisteredException.class,
-                () -> transportManager.getTransportDataManagementLabel(mTransport2.name));
+                () -> transportManager.getTransportDataManagementLabel(mTransportA2.transportName));
         expectThrows(
                 TransportNotRegisteredException.class,
-                () -> transportManager.getTransportDirName(mTransport2.name));
+                () -> transportManager.getTransportDirName(mTransportA2.transportName));
     }
 
-    private void setUpPackageWithTransports(String packageName, List<TransportInfo> transports,
-            int flags) throws Exception {
+    private List<TransportMock> setUpTransports(TransportData... transports) throws Exception {
+        setUpTransportsForTransportManager(mShadowPackageManager, transports);
+        List<TransportMock> transportMocks = new ArrayList<>(transports.length);
+        for (TransportData transport : transports) {
+            TransportMock transportMock = mockTransport(transport);
+            when(mTransportClientManager.getTransportClient(
+                            eq(transport.getTransportComponent()), any()))
+                    .thenReturn(transportMock.transportClient);
+            transportMocks.add(transportMock);
+        }
+        return transportMocks;
+    }
+
+    private void setUpPackage(String packageName, int flags) {
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = packageName;
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.privateFlags = flags;
-
-        mPackageManagerShadow.addPackage(packageInfo);
-
-        List<ResolveInfo> transportsInfo = new ArrayList<>();
-        for (TransportInfo transport : transports) {
-            ResolveInfo info = new ResolveInfo();
-            info.serviceInfo = new ServiceInfo();
-            info.serviceInfo.packageName = packageName;
-            info.serviceInfo.name = transport.name;
-            transportsInfo.add(info);
-        }
-
-        Intent intent = new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST);
-        intent.setPackage(packageName);
-
-        mPackageManagerShadow.addResolveInfoForIntent(intent, transportsInfo);
+        mShadowPackageManager.addPackage(packageInfo);
     }
 
-    private TransportManager createTransportManagerAndSetUpTransports(
-            List<TransportInfo> availableTransports, String defaultTransportName) throws Exception {
-        return createTransportManagerAndSetUpTransports(availableTransports,
-                Collections.<TransportInfo>emptyList(), defaultTransportName);
-    }
-
-    private TransportManager createTransportManagerAndSetUpTransports(
-            List<TransportInfo> availableTransports, List<TransportInfo> unavailableTransports,
-            String defaultTransportName)
-            throws Exception {
-        List<String> availableTransportsNames = new ArrayList<>();
-        List<ComponentName> availableTransportsComponentNames = new ArrayList<>();
-        for (TransportInfo transport : availableTransports) {
-            availableTransportsNames.add(transport.name);
-            availableTransportsComponentNames.add(transport.componentName);
-        }
-
-        List<ComponentName> allTransportsComponentNames = new ArrayList<>();
-        allTransportsComponentNames.addAll(availableTransportsComponentNames);
-        for (TransportInfo transport : unavailableTransports) {
-            allTransportsComponentNames.add(transport.componentName);
-        }
-
-        for (TransportInfo transport : unavailableTransports) {
-            ShadowContextImplForBackup.sUnbindableComponents.add(transport.componentName);
-        }
-
-        setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
-                ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
-
-        TransportManager transportManager = new TransportManager(
-                RuntimeEnvironment.application.getApplicationContext(),
-                new HashSet<>(allTransportsComponentNames),
-                defaultTransportName,
-                mTransportBoundListenerStub,
-                ShadowLooper.getMainLooper());
-        transportManager.onPackageAdded(PACKAGE_NAME);
-
-        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
-                availableTransportsComponentNames);
-        assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
-                availableTransportsNames);
-        for (TransportInfo transport : availableTransports) {
-            assertThat(mTransportBoundListenerStub.isCalledForTransport(transport.binderInterface))
-                    .isTrue();
-        }
-        for (TransportInfo transport : unavailableTransports) {
-            assertThat(mTransportBoundListenerStub.isCalledForTransport(transport.binderInterface))
-                    .isFalse();
-        }
-
-        mTransportBoundListenerStub.resetState();
-
+    private TransportManager createTransportManager(
+            @Nullable TransportData selectedTransport, TransportData... transports) {
+        Set<ComponentName> whitelist =
+                concat(Stream.of(selectedTransport), Stream.of(transports))
+                        .filter(Objects::nonNull)
+                        .map(TransportData::getTransportComponent)
+                        .collect(toSet());
+        TransportManager transportManager =
+                new TransportManager(
+                        mContext,
+                        whitelist,
+                        selectedTransport != null ? selectedTransport.transportName : null,
+                        mTransportClientManager);
+        transportManager.setOnTransportRegisteredListener(mListener);
         return transportManager;
     }
 
-    private static class TransportInfo {
-        public final String packageName;
-        public final String name;
-        public final ComponentName componentName;
-        public final IBackupTransport binderInterface;
-        public final IBinder binder;
-
-        TransportInfo(
-                String packageName,
-                String name,
-                @Nullable Intent configurationIntent,
-                String currentDestinationString,
-                @Nullable Intent dataManagementIntent,
-                String dataManagementLabel) {
-            this.packageName = packageName;
-            this.name = name;
-            this.componentName = new ComponentName(packageName, name);
-            this.binder = mock(IBinder.class);
-            IBackupTransport transport = mock(IBackupTransport.class);
-            try {
-                when(transport.name()).thenReturn(name);
-                when(transport.configurationIntent()).thenReturn(configurationIntent);
-                when(transport.currentDestinationString()).thenReturn(currentDestinationString);
-                when(transport.dataManagementIntent()).thenReturn(dataManagementIntent);
-                when(transport.dataManagementLabel()).thenReturn(dataManagementLabel);
-            } catch (RemoteException e) {
-                // Only here to mock methods that throw RemoteException
-            }
-            this.binderInterface = transport;
-        }
+    private void assertRegisteredTransports(
+            TransportManager transportManager, List<TransportData> transports) {
+        assertThat(transportManager.getRegisteredTransportComponents())
+                .asList()
+                .containsExactlyElementsIn(
+                        transports
+                                .stream()
+                                .map(TransportData::getTransportComponent)
+                                .collect(toList()));
+        assertThat(transportManager.getRegisteredTransportNames())
+                .asList()
+                .containsExactlyElementsIn(
+                        transports.stream().map(t -> t.transportName).collect(toList()));
     }
-
 }
diff --git a/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java b/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java
index dfca901..ace0441 100644
--- a/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java
@@ -19,8 +19,10 @@
 import static android.app.backup.BackupTransport.TRANSPORT_ERROR;
 import static android.app.backup.BackupTransport.TRANSPORT_OK;
 
-import static com.android.server.backup.testing.TransportTestUtils.TRANSPORT_NAME;
-import static com.android.server.backup.testing.TransportTestUtils.TRANSPORT_NAMES;
+import static com.android.server.backup.testing.TransportData.backupTransport;
+import static com.android.server.backup.testing.TransportData.d2dTransport;
+import static com.android.server.backup.testing.TransportData.localTransport;
+import static com.android.server.backup.testing.TransportTestUtils.setUpTransports;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -28,7 +30,6 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -44,7 +45,8 @@
 import com.android.server.backup.RefactoredBackupManagerService;
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.testing.TransportTestUtils;
-import com.android.server.backup.testing.TransportTestUtils.TransportData;
+import com.android.server.backup.testing.TransportData;
+import com.android.server.backup.testing.TransportTestUtils.TransportMock;
 import com.android.server.backup.transport.TransportClient;
 import com.android.server.testing.FrameworkRobolectricTestRunner;
 import com.android.server.testing.SystemLoaderClasses;
@@ -58,7 +60,10 @@
 import org.robolectric.annotation.Config;
 
 import java.io.File;
+import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
+import java.util.stream.Stream;
 
 @RunWith(FrameworkRobolectricTestRunner.class)
 @Config(manifest = Config.NONE, sdk = 26)
@@ -68,16 +73,21 @@
     @Mock private RefactoredBackupManagerService mBackupManagerService;
     @Mock private TransportManager mTransportManager;
     @Mock private OnTaskFinishedListener mListener;
-    @Mock private IBackupTransport mTransport;
+    @Mock private IBackupTransport mTransportBinder;
     @Mock private IBackupObserver mObserver;
     @Mock private AlarmManager mAlarmManager;
     @Mock private PendingIntent mRunInitIntent;
     private File mBaseStateDir;
+    private TransportData mTransport;
+    private String mTransportName;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mTransport = backupTransport();
+        mTransportName = mTransport.transportName;
+
         Application context = RuntimeEnvironment.application;
         mBaseStateDir = new File(context.getCacheDir(), "base_state_dir");
         assertThat(mBaseStateDir.mkdir()).isTrue();
@@ -88,82 +98,76 @@
 
     @Test
     public void testRun_callsTransportCorrectly() throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_OK);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_OK);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
-        verify(mTransport).initializeDevice();
-        verify(mTransport).finishBackup();
+        verify(mTransportBinder).initializeDevice();
+        verify(mTransportBinder).finishBackup();
     }
 
     @Test
     public void testRun_callsBackupManagerCorrectly() throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_OK);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_OK);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
         verify(mBackupManagerService)
-                .recordInitPending(
-                        false, TRANSPORT_NAME, TransportTestUtils.transportDirName(TRANSPORT_NAME));
+                .recordInitPending(false, mTransportName, mTransport.transportDirName);
         verify(mBackupManagerService)
-                .resetBackupState(
-                        eq(
-                                new File(
-                                        mBaseStateDir,
-                                        TransportTestUtils.transportDirName(TRANSPORT_NAME))));
+                .resetBackupState(eq(new File(mBaseStateDir, mTransport.transportDirName)));
     }
 
     @Test
     public void testRun_callsObserverAndListenerCorrectly() throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_OK);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_OK);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
-        verify(mObserver).onResult(eq(TRANSPORT_NAME), eq(TRANSPORT_OK));
+        verify(mObserver).onResult(eq(mTransportName), eq(TRANSPORT_OK));
         verify(mObserver).backupFinished(eq(TRANSPORT_OK));
         verify(mListener).onFinished(any());
     }
 
     @Test
     public void testRun_whenInitializeDeviceFails() throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_ERROR, 0);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_ERROR, 0);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
-        verify(mTransport).initializeDevice();
-        verify(mTransport, never()).finishBackup();
+        verify(mTransportBinder).initializeDevice();
+        verify(mTransportBinder, never()).finishBackup();
         verify(mBackupManagerService)
-                .recordInitPending(
-                        true, TRANSPORT_NAME, TransportTestUtils.transportDirName(TRANSPORT_NAME));
+                .recordInitPending(true, mTransportName, mTransport.transportDirName);
     }
 
     @Test
     public void testRun_whenInitializeDeviceFails_callsObserverAndListenerCorrectly()
             throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_ERROR, 0);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_ERROR, 0);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
-        verify(mObserver).onResult(eq(TRANSPORT_NAME), eq(TRANSPORT_ERROR));
+        verify(mObserver).onResult(eq(mTransportName), eq(TRANSPORT_ERROR));
         verify(mObserver).backupFinished(eq(TRANSPORT_ERROR));
         verify(mListener).onFinished(any());
     }
 
     @Test
     public void testRun_whenInitializeDeviceFails_schedulesAlarm() throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_ERROR, 0);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_ERROR, 0);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
@@ -172,37 +176,36 @@
 
     @Test
     public void testRun_whenFinishBackupFails() throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_ERROR);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_ERROR);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
-        verify(mTransport).initializeDevice();
-        verify(mTransport).finishBackup();
+        verify(mTransportBinder).initializeDevice();
+        verify(mTransportBinder).finishBackup();
         verify(mBackupManagerService)
-                .recordInitPending(
-                        true, TRANSPORT_NAME, TransportTestUtils.transportDirName(TRANSPORT_NAME));
+                .recordInitPending(true, mTransportName, mTransport.transportDirName);
     }
 
     @Test
     public void testRun_whenFinishBackupFails_callsObserverAndListenerCorrectly() throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_ERROR);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_ERROR);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
-        verify(mObserver).onResult(eq(TRANSPORT_NAME), eq(TRANSPORT_ERROR));
+        verify(mObserver).onResult(eq(mTransportName), eq(TRANSPORT_ERROR));
         verify(mObserver).backupFinished(eq(TRANSPORT_ERROR));
         verify(mListener).onFinished(any());
     }
 
     @Test
     public void testRun_whenFinishBackupFails_schedulesAlarm() throws Exception {
-        setUpTransport(TRANSPORT_NAME);
-        configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_ERROR);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransport(mTransport);
+        configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_ERROR);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
@@ -211,64 +214,76 @@
 
     @Test
     public void testRun_whenOnlyOneTransportFails() throws Exception {
-        List<TransportData> transports =
-                TransportTestUtils.setUpTransports(
-                        mTransportManager, TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
-        configureTransport(transports.get(0).transportMock, TRANSPORT_ERROR, 0);
-        configureTransport(transports.get(1).transportMock, TRANSPORT_OK, TRANSPORT_OK);
+        TransportData transport1 = backupTransport();
+        TransportData transport2 = d2dTransport();
+        List<TransportMock> transportMocks =
+                setUpTransports(mTransportManager, transport1, transport2);
+        configureTransport(transportMocks.get(0).transport, TRANSPORT_ERROR, 0);
+        configureTransport(transportMocks.get(1).transport, TRANSPORT_OK, TRANSPORT_OK);
         PerformInitializeTask performInitializeTask =
-                createPerformInitializeTask(TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
+                createPerformInitializeTask(transport1.transportName, transport2.transportName);
 
         performInitializeTask.run();
 
-        verify(transports.get(1).transportMock).initializeDevice();
-        verify(mObserver).onResult(eq(TRANSPORT_NAMES[0]), eq(TRANSPORT_ERROR));
-        verify(mObserver).onResult(eq(TRANSPORT_NAMES[1]), eq(TRANSPORT_OK));
+        verify(transportMocks.get(1).transport).initializeDevice();
+        verify(mObserver).onResult(eq(transport1.transportName), eq(TRANSPORT_ERROR));
+        verify(mObserver).onResult(eq(transport2.transportName), eq(TRANSPORT_OK));
         verify(mObserver).backupFinished(eq(TRANSPORT_ERROR));
     }
 
     @Test
     public void testRun_withMultipleTransports() throws Exception {
-        List<TransportData> transports =
-                TransportTestUtils.setUpTransports(mTransportManager, TRANSPORT_NAMES);
-        configureTransport(transports.get(0).transportMock, TRANSPORT_OK, TRANSPORT_OK);
-        configureTransport(transports.get(1).transportMock, TRANSPORT_OK, TRANSPORT_OK);
-        configureTransport(transports.get(2).transportMock, TRANSPORT_OK, TRANSPORT_OK);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAMES);
+        List<TransportMock> transportMocks =
+                setUpTransports(
+                        mTransportManager, backupTransport(), d2dTransport(), localTransport());
+        configureTransport(transportMocks.get(0).transport, TRANSPORT_OK, TRANSPORT_OK);
+        configureTransport(transportMocks.get(1).transport, TRANSPORT_OK, TRANSPORT_OK);
+        configureTransport(transportMocks.get(2).transport, TRANSPORT_OK, TRANSPORT_OK);
+        String[] transportNames =
+                Stream.of(new TransportData[] {backupTransport(), d2dTransport(), localTransport()})
+                        .map(t -> t.transportName)
+                        .toArray(String[]::new);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(transportNames);
 
         performInitializeTask.run();
 
-        for (TransportData transport : transports) {
+        Iterator<TransportData> transportsIterator =
+                Arrays.asList(
+                                new TransportData[] {
+                                    backupTransport(), d2dTransport(), localTransport()
+                                })
+                        .iterator();
+        for (TransportMock transportMock : transportMocks) {
+            TransportData transport = transportsIterator.next();
             verify(mTransportManager).getTransportClient(eq(transport.transportName), any());
             verify(mTransportManager)
-                    .disposeOfTransportClient(eq(transport.transportClientMock), any());
+                    .disposeOfTransportClient(eq(transportMock.transportClient), any());
         }
     }
 
     @Test
     public void testRun_whenOnlyOneTransportFails_disposesAllTransports() throws Exception {
-        List<TransportData> transports =
-                TransportTestUtils.setUpTransports(
-                        mTransportManager, TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
-        configureTransport(transports.get(0).transportMock, TRANSPORT_ERROR, 0);
-        configureTransport(transports.get(1).transportMock, TRANSPORT_OK, TRANSPORT_OK);
+        TransportData transport1 = backupTransport();
+        TransportData transport2 = d2dTransport();
+        List<TransportMock> transportMocks =
+                setUpTransports(mTransportManager, transport1, transport2);
+        configureTransport(transportMocks.get(0).transport, TRANSPORT_ERROR, 0);
+        configureTransport(transportMocks.get(1).transport, TRANSPORT_OK, TRANSPORT_OK);
         PerformInitializeTask performInitializeTask =
-                createPerformInitializeTask(TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
+                createPerformInitializeTask(transport1.transportName, transport2.transportName);
 
         performInitializeTask.run();
 
         verify(mTransportManager)
-                .disposeOfTransportClient(eq(transports.get(0).transportClientMock), any());
+                .disposeOfTransportClient(eq(transportMocks.get(0).transportClient), any());
         verify(mTransportManager)
-                .disposeOfTransportClient(eq(transports.get(1).transportClientMock), any());
+                .disposeOfTransportClient(eq(transportMocks.get(1).transportClient), any());
     }
 
     @Test
     public void testRun_whenTransportNotRegistered() throws Exception {
-        TransportTestUtils.setUpTransports(
-                mTransportManager, new TransportData(TRANSPORT_NAME, null, null));
-
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        setUpTransports(mTransportManager, mTransport.unregistered());
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
@@ -279,16 +294,15 @@
 
     @Test
     public void testRun_whenOnlyOneTransportNotRegistered() throws Exception {
-        List<TransportData> transports =
-                TransportTestUtils.setUpTransports(
-                        mTransportManager,
-                        new TransportData(TRANSPORT_NAMES[0], null, null),
-                        new TransportData(TRANSPORT_NAMES[1]));
-        String registeredTransportName = transports.get(1).transportName;
-        IBackupTransport registeredTransport = transports.get(1).transportMock;
-        TransportClient registeredTransportClient = transports.get(1).transportClientMock;
+        TransportData transport1 = backupTransport().unregistered();
+        TransportData transport2 = d2dTransport();
+        List<TransportMock> transportMocks =
+                setUpTransports(mTransportManager, transport1, transport2);
+        String registeredTransportName = transport2.transportName;
+        IBackupTransport registeredTransport = transportMocks.get(1).transport;
+        TransportClient registeredTransportClient = transportMocks.get(1).transportClient;
         PerformInitializeTask performInitializeTask =
-                createPerformInitializeTask(TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
+                createPerformInitializeTask(transport1.transportName, transport2.transportName);
 
         performInitializeTask.run();
 
@@ -299,25 +313,24 @@
 
     @Test
     public void testRun_whenTransportNotAvailable() throws Exception {
-        TransportClient transportClient = mock(TransportClient.class);
-        TransportTestUtils.setUpTransports(
-                mTransportManager, new TransportData(TRANSPORT_NAME, null, transportClient));
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        TransportMock transportMock = setUpTransport(mTransport.unavailable());
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
-        verify(mTransportManager).disposeOfTransportClient(eq(transportClient), any());
+        verify(mTransportManager)
+                .disposeOfTransportClient(eq(transportMock.transportClient), any());
         verify(mObserver).backupFinished(eq(TRANSPORT_ERROR));
         verify(mListener).onFinished(any());
     }
 
     @Test
     public void testRun_whenTransportThrowsDeadObjectException() throws Exception {
-        TransportClient transportClient = mock(TransportClient.class);
-        TransportTestUtils.setUpTransports(
-                mTransportManager, new TransportData(TRANSPORT_NAME, mTransport, transportClient));
-        when(mTransport.initializeDevice()).thenThrow(DeadObjectException.class);
-        PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transport = transportMock.transport;
+        TransportClient transportClient = transportMock.transportClient;
+        when(transport.initializeDevice()).thenThrow(DeadObjectException.class);
+        PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
 
         performInitializeTask.run();
 
@@ -343,9 +356,10 @@
         when(transportMock.finishBackup()).thenReturn(finishBackupStatus);
     }
 
-    private void setUpTransport(String transportName) throws Exception {
-        TransportTestUtils.setUpTransport(
-                mTransportManager,
-                new TransportData(transportName, mTransport, mock(TransportClient.class)));
+    private TransportMock setUpTransport(TransportData transport) throws Exception {
+        TransportMock transportMock =
+                TransportTestUtils.setUpTransport(mTransportManager, transport);
+        mTransportBinder = transportMock.transport;
+        return transportMock;
     }
 }
diff --git a/services/robotests/src/com/android/server/backup/testing/ShadowBackupPolicyEnforcer.java b/services/robotests/src/com/android/server/backup/testing/ShadowBackupPolicyEnforcer.java
new file mode 100644
index 0000000..88b30da
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/testing/ShadowBackupPolicyEnforcer.java
@@ -0,0 +1,24 @@
+package com.android.server.backup.testing;
+
+import android.content.ComponentName;
+
+import com.android.server.backup.BackupPolicyEnforcer;
+import com.android.server.backup.RefactoredBackupManagerService;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(BackupPolicyEnforcer.class)
+public class ShadowBackupPolicyEnforcer {
+
+    private static ComponentName sMandatoryBackupTransport;
+
+    public static void setMandatoryBackupTransport(ComponentName backupTransportComponent) {
+        sMandatoryBackupTransport = backupTransportComponent;
+    }
+
+    @Implementation
+    public ComponentName getMandatoryBackupTransport() {
+        return sMandatoryBackupTransport;
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/TestUtils.java b/services/robotests/src/com/android/server/backup/testing/TestUtils.java
new file mode 100644
index 0000000..1be298d
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/testing/TestUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.testing;
+
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+
+import java.util.concurrent.Callable;
+
+public class TestUtils {
+    /**
+     * Calls {@link Runnable#run()} and returns if no exception is thrown. Otherwise, if the
+     * exception is unchecked, rethrow it; if it's checked wrap in a {@link RuntimeException} and
+     * throw.
+     *
+     * <p><b>Warning:</b>DON'T use this outside tests. A wrapped checked exception is just a failure
+     * in a test.
+     */
+    public static void uncheck(ThrowingRunnable runnable) {
+        try {
+            runnable.runOrThrow();
+        } catch (Exception e) {
+            throw wrapIfChecked(e);
+        }
+    }
+
+    /**
+     * Calls {@link Callable#call()} and returns the value if no exception is thrown. Otherwise, if
+     * the exception is unchecked, rethrow it; if it's checked wrap in a {@link RuntimeException}
+     * and throw.
+     *
+     * <p><b>Warning:</b>DON'T use this outside tests. A wrapped checked exception is just a failure
+     * in a test.
+     */
+    public static <T> T uncheck(Callable<T> callable) {
+        try {
+            return callable.call();
+        } catch (Exception e) {
+            throw wrapIfChecked(e);
+        }
+    }
+
+    /**
+     * Wrap {@code e} in a {@link RuntimeException} only if it's not one already, in which case it's
+     * returned.
+     */
+    public static RuntimeException wrapIfChecked(Exception e) {
+        if (e instanceof RuntimeException) {
+            return (RuntimeException) e;
+        }
+        return new RuntimeException(e);
+    }
+
+    private TestUtils() {}
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java b/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java
deleted file mode 100644
index 84ac2c2..0000000
--- a/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.backup.testing;
-
-import com.android.internal.backup.IBackupTransport;
-import com.android.server.backup.TransportManager;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Stub implementation of TransportBoundListener, which returns given result and can tell whether
- * it was called for given transport.
- */
-public class TransportBoundListenerStub implements
-        TransportManager.TransportBoundListener {
-    private boolean mAlwaysReturnSuccess;
-    private Set<IBackupTransport> mTransportsCalledFor = new HashSet<>();
-
-    public TransportBoundListenerStub(boolean alwaysReturnSuccess) {
-        this.mAlwaysReturnSuccess = alwaysReturnSuccess;
-    }
-
-    @Override
-    public boolean onTransportBound(IBackupTransport binder) {
-        mTransportsCalledFor.add(binder);
-        return mAlwaysReturnSuccess;
-    }
-
-    /**
-     * Returns whether the listener was called for the specified transport at least once.
-     */
-    public boolean isCalledForTransport(IBackupTransport binder) {
-        return mTransportsCalledFor.contains(binder);
-    }
-
-    /**
-     * Returns whether the listener was called at least once.
-     */
-    public boolean isCalled() {
-        return !mTransportsCalledFor.isEmpty();
-    }
-
-    /**
-     * Resets listener calls.
-     */
-    public void resetState() {
-        mTransportsCalledFor.clear();
-    }
-}
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportData.java b/services/robotests/src/com/android/server/backup/testing/TransportData.java
new file mode 100644
index 0000000..9feaa8e
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/testing/TransportData.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.testing;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+
+public class TransportData {
+    // No constants since new Intent() can't be called in static context because of Robolectric
+    public static TransportData backupTransport() {
+        return new TransportData(
+                "com.google.android.gms/.backup.BackupTransportService",
+                "com.google.android.gms/.backup.BackupTransportService",
+                "com.google.android.gms.backup.BackupTransportService",
+                new Intent(),
+                "user@gmail.com",
+                new Intent(),
+                "Google Account");
+    }
+
+    public static TransportData d2dTransport() {
+        return new TransportData(
+                "com.google.android.gms/.backup.migrate.service.D2dTransport",
+                "com.google.android.gms/.backup.component.D2dTransportService",
+                "d2dMigrateTransport",
+                null,
+                "Moving data to new device",
+                null,
+                "");
+    }
+
+    public static TransportData localTransport() {
+        return new TransportData(
+                "android/com.android.internal.backup.LocalTransport",
+                "android/com.android.internal.backup.LocalTransportService",
+                "com.android.internal.backup.LocalTransport",
+                null,
+                "Backing up to debug-only private cache",
+                null,
+                "");
+    }
+
+    public static TransportData genericTransport(String packageName, String className) {
+        return new TransportData(
+                packageName + "/." + className,
+                packageName + "/." + className + "Service",
+                packageName + "." + className,
+                new Intent(),
+                "currentDestinationString",
+                new Intent(),
+                "dataManagementLabel");
+    }
+
+    @TransportTestUtils.TransportStatus
+    public int transportStatus;
+    public final String transportName;
+    private final String transportComponentShort;
+    @Nullable
+    public String transportDirName;
+    @Nullable public Intent configurationIntent;
+    @Nullable public String currentDestinationString;
+    @Nullable public Intent dataManagementIntent;
+    @Nullable public String dataManagementLabel;
+
+    private TransportData(
+            @TransportTestUtils.TransportStatus int transportStatus,
+            String transportName,
+            String transportComponentShort,
+            String transportDirName,
+            Intent configurationIntent,
+            String currentDestinationString,
+            Intent dataManagementIntent,
+            String dataManagementLabel) {
+        this.transportStatus = transportStatus;
+        this.transportName = transportName;
+        this.transportComponentShort = transportComponentShort;
+        this.transportDirName = transportDirName;
+        this.configurationIntent = configurationIntent;
+        this.currentDestinationString = currentDestinationString;
+        this.dataManagementIntent = dataManagementIntent;
+        this.dataManagementLabel = dataManagementLabel;
+    }
+
+    public TransportData(
+            String transportName,
+            String transportComponentShort,
+            String transportDirName,
+            Intent configurationIntent,
+            String currentDestinationString,
+            Intent dataManagementIntent,
+            String dataManagementLabel) {
+        this(
+                TransportTestUtils.TransportStatus.REGISTERED_AVAILABLE,
+                transportName,
+                transportComponentShort,
+                transportDirName,
+                configurationIntent,
+                currentDestinationString,
+                dataManagementIntent,
+                dataManagementLabel);
+    }
+
+    /**
+     * Not field because otherwise we'd have to call ComponentName::new in static context and
+     * Robolectric does not like this.
+     */
+    public ComponentName getTransportComponent() {
+        return ComponentName.unflattenFromString(transportComponentShort);
+    }
+
+    public TransportData unavailable() {
+        return new TransportData(
+                TransportTestUtils.TransportStatus.REGISTERED_UNAVAILABLE,
+                transportName,
+                transportComponentShort,
+                transportDirName,
+                configurationIntent,
+                currentDestinationString,
+                dataManagementIntent,
+                dataManagementLabel);
+    }
+
+    public TransportData unregistered() {
+        return new TransportData(
+                TransportTestUtils.TransportStatus.UNREGISTERED,
+                transportName,
+                transportComponentShort,
+                transportDirName,
+                configurationIntent,
+                currentDestinationString,
+                dataManagementIntent,
+                dataManagementLabel);
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
index 9770e40..e1dc7b5 100644
--- a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
+++ b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
@@ -16,13 +16,23 @@
 
 package com.android.server.backup.testing;
 
+import static com.android.server.backup.testing.TestUtils.uncheck;
+
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import static java.util.stream.Collectors.toList;
+
 import android.annotation.Nullable;
 import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.support.annotation.IntDef;
 
 import com.android.internal.backup.IBackupTransport;
 import com.android.server.backup.TransportManager;
@@ -30,85 +40,82 @@
 import com.android.server.backup.transport.TransportNotAvailableException;
 import com.android.server.backup.transport.TransportNotRegisteredException;
 
-import java.util.Arrays;
+import org.robolectric.shadows.ShadowPackageManager;
+
 import java.util.List;
+import java.util.stream.Stream;
 
 public class TransportTestUtils {
-    public static final String[] TRANSPORT_NAMES = {
-        "android/com.android.internal.backup.LocalTransport",
-        "com.google.android.gms/.backup.migrate.service.D2dTransport",
-        "com.google.android.gms/.backup.BackupTransportService"
-    };
+    /**
+     * Differently from {@link #setUpTransports(TransportManager, TransportData...)}, which
+     * configures {@link TransportManager}, this is meant to mock the environment for a real
+     * TransportManager.
+     */
+    public static void setUpTransportsForTransportManager(
+            ShadowPackageManager shadowPackageManager, TransportData... transports)
+            throws Exception {
+        for (TransportData transport : transports) {
+            ComponentName transportComponent = transport.getTransportComponent();
+            String packageName = transportComponent.getPackageName();
+            ResolveInfo resolveInfo = resolveInfo(transportComponent);
+            shadowPackageManager.addResolveInfoForIntent(transportIntent(), resolveInfo);
+            shadowPackageManager.addResolveInfoForIntent(
+                    transportIntent().setPackage(packageName), resolveInfo);
+        }
+    }
 
-    public static final String TRANSPORT_NAME = TRANSPORT_NAMES[0];
+    private static Intent transportIntent() {
+        return new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST);
+    }
 
-    /** {@code transportName} has to be in the {@link ComponentName} format (with '/') */
-    public static TransportData setUpCurrentTransport(
-            TransportManager transportManager, String transportName) throws Exception {
-        TransportData transport = setUpTransports(transportManager, transportName).get(0);
-        when(transportManager.getCurrentTransportClient(any()))
-                .thenReturn(transport.transportClientMock);
-        return transport;
+    private static ResolveInfo resolveInfo(ComponentName transportComponent) {
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.serviceInfo = new ServiceInfo();
+        resolveInfo.serviceInfo.packageName = transportComponent.getPackageName();
+        resolveInfo.serviceInfo.name = transportComponent.getClassName();
+        return resolveInfo;
     }
 
     /** {@code transportName} has to be in the {@link ComponentName} format (with '/') */
-    public static List<TransportData> setUpTransports(
-            TransportManager transportManager, String... transportNames) throws Exception {
-        return setUpTransports(
-                transportManager,
-                Arrays.stream(transportNames)
-                        .map(TransportData::new)
-                        .toArray(TransportData[]::new));
+    public static TransportMock setUpCurrentTransport(
+            TransportManager transportManager, TransportData transport) throws Exception {
+        TransportMock transportMock = setUpTransports(transportManager, transport).get(0);
+        if (transportMock.transportClient != null) {
+            when(transportManager.getCurrentTransportClient(any()))
+                    .thenReturn(transportMock.transportClient);
+        }
+        return transportMock;
     }
 
     /** @see #setUpTransport(TransportManager, TransportData) */
-    public static List<TransportData> setUpTransports(
+    public static List<TransportMock> setUpTransports(
             TransportManager transportManager, TransportData... transports) throws Exception {
-        for (TransportData transport : transports) {
-            setUpTransport(transportManager, transport);
-        }
-        return Arrays.asList(transports);
+        return Stream.of(transports)
+                .map(transport -> uncheck(() -> setUpTransport(transportManager, transport)))
+                .collect(toList());
     }
 
-    /**
-     * Configures transport according to {@link TransportData}:
-     *
-     * <ul>
-     *   <li>{@link TransportData#transportMock} {@code null} means transport not available.
-     *   <li>{@link TransportData#transportClientMock} {@code null} means transport not registered.
-     * </ul>
-     */
-    public static void setUpTransport(TransportManager transportManager, TransportData transport)
-            throws Exception {
+    public static TransportMock setUpTransport(
+            TransportManager transportManager, TransportData transport) throws Exception {
+        int status = transport.transportStatus;
         String transportName = transport.transportName;
-        String transportDirName = transportDirName(transportName);
-        ComponentName transportComponent = transportComponentName(transportName);
-        IBackupTransport transportMock = transport.transportMock;
-        TransportClient transportClientMock = transport.transportClientMock;
+        ComponentName transportComponent = transport.getTransportComponent();
+        String transportDirName = transport.transportDirName;
 
-        if (transportClientMock != null) {
+        TransportMock transportMock = mockTransport(transport);
+        if (status == TransportStatus.REGISTERED_AVAILABLE
+                || status == TransportStatus.REGISTERED_UNAVAILABLE) {
             // Transport registered
             when(transportManager.getTransportClient(eq(transportName), any()))
-                    .thenReturn(transportClientMock);
+                    .thenReturn(transportMock.transportClient);
             when(transportManager.getTransportClientOrThrow(eq(transportName), any()))
-                    .thenReturn(transportClientMock);
+                    .thenReturn(transportMock.transportClient);
             when(transportManager.getTransportName(transportComponent)).thenReturn(transportName);
             when(transportManager.getTransportDirName(eq(transportName)))
                     .thenReturn(transportDirName);
             when(transportManager.getTransportDirName(eq(transportComponent)))
                     .thenReturn(transportDirName);
-            when(transportClientMock.getTransportComponent()).thenReturn(transportComponent);
-
-            if (transportMock != null) {
-                // Transport registered and available
-                when(transportClientMock.connectOrThrow(any())).thenReturn(transportMock);
-                when(transportMock.name()).thenReturn(transportName);
-                when(transportMock.transportDirName()).thenReturn(transportDirName);
-            } else {
-                // Transport registered but unavailable
-                when(transportClientMock.connectOrThrow(any()))
-                        .thenThrow(TransportNotAvailableException.class);
-            }
+            // TODO: Mock rest of description methods
         } else {
             // Transport not registered
             when(transportManager.getTransportClient(eq(transportName), any())).thenReturn(null);
@@ -121,34 +128,73 @@
             when(transportManager.getTransportDirName(eq(transportComponent)))
                     .thenThrow(TransportNotRegisteredException.class);
         }
+        return transportMock;
     }
 
-    /** {@code transportName} has to be in the {@link ComponentName} format (with '/') */
-    public static ComponentName transportComponentName(String transportName) {
-        return ComponentName.unflattenFromString(transportName);
-    }
+    public static TransportMock mockTransport(TransportData transport) throws Exception {
+        final TransportClient transportClientMock;
+        int status = transport.transportStatus;
+        ComponentName transportComponent = transport.getTransportComponent();
+        if (status == TransportStatus.REGISTERED_AVAILABLE
+                || status == TransportStatus.REGISTERED_UNAVAILABLE) {
+            // Transport registered
+            transportClientMock = mock(TransportClient.class);
+            when(transportClientMock.getTransportComponent()).thenReturn(transportComponent);
+            if (status == TransportStatus.REGISTERED_AVAILABLE) {
+                // Transport registered and available
+                IBackupTransport transportMock = mockTransportBinder(transport);
+                when(transportClientMock.connectOrThrow(any())).thenReturn(transportMock);
 
-    public static String transportDirName(String transportName) {
-        return transportName + "_dir_name";
-    }
+                return new TransportMock(transportClientMock, transportMock);
+            } else {
+                // Transport registered but unavailable
+                when(transportClientMock.connectOrThrow(any()))
+                        .thenThrow(TransportNotAvailableException.class);
 
-    public static class TransportData {
-        public final String transportName;
-        @Nullable public final IBackupTransport transportMock;
-        @Nullable public final TransportClient transportClientMock;
-
-        public TransportData(
-                String transportName,
-                @Nullable IBackupTransport transportMock,
-                @Nullable TransportClient transportClientMock) {
-            this.transportName = transportName;
-            this.transportMock = transportMock;
-            this.transportClientMock = transportClientMock;
+                return new TransportMock(transportClientMock, null);
+            }
+        } else {
+            // Transport not registered
+            return new TransportMock(null, null);
         }
+    }
 
-        public TransportData(String transportName) {
-            this(transportName, mock(IBackupTransport.class), mock(TransportClient.class));
+    private static IBackupTransport mockTransportBinder(TransportData transport) throws Exception {
+        IBackupTransport transportBinder = mock(IBackupTransport.class);
+        try {
+            when(transportBinder.name()).thenReturn(transport.transportName);
+            when(transportBinder.transportDirName()).thenReturn(transport.transportDirName);
+            when(transportBinder.configurationIntent()).thenReturn(transport.configurationIntent);
+            when(transportBinder.currentDestinationString())
+                    .thenReturn(transport.currentDestinationString);
+            when(transportBinder.dataManagementIntent()).thenReturn(transport.dataManagementIntent);
+            when(transportBinder.dataManagementLabel()).thenReturn(transport.dataManagementLabel);
+        } catch (RemoteException e) {
+            fail("RemoteException?");
         }
+        return transportBinder;
+    }
+
+    public static class TransportMock {
+        @Nullable public final TransportClient transportClient;
+        @Nullable public final IBackupTransport transport;
+
+        private TransportMock(
+                @Nullable TransportClient transportClient, @Nullable IBackupTransport transport) {
+            this.transportClient = transportClient;
+            this.transport = transport;
+        }
+    }
+
+    @IntDef({
+        TransportStatus.REGISTERED_AVAILABLE,
+        TransportStatus.REGISTERED_UNAVAILABLE,
+        TransportStatus.UNREGISTERED
+    })
+    public @interface TransportStatus {
+        int REGISTERED_AVAILABLE = 0;
+        int REGISTERED_UNAVAILABLE = 1;
+        int UNREGISTERED = 2;
     }
 
     private TransportTestUtils() {}
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
index 3bc0b30..9b4dec6 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
@@ -17,9 +17,7 @@
 package com.android.server.backup.transport;
 
 import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -36,12 +34,10 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
-
 import com.android.internal.backup.IBackupTransport;
 import com.android.server.backup.TransportManager;
 import com.android.server.testing.FrameworkRobolectricTestRunner;
 import com.android.server.testing.SystemLoaderClasses;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -78,11 +74,7 @@
         mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
         mTransportClient =
                 new TransportClient(
-                        mContext,
-                        mBindIntent,
-                        mTransportComponent,
-                        "1",
-                        new Handler(mainLooper));
+                        mContext, mBindIntent, mTransportComponent, "1", new Handler(mainLooper));
 
         when(mContext.bindServiceAsUser(
                         eq(mBindIntent),
@@ -213,32 +205,34 @@
                 .onTransportConnectionResult(isNull(), eq(mTransportClient));
     }
 
-    // TODO(b/69153972): Support SDK 26 API (ServiceConnection.inBindingDied) for transport tests
-    /*@Test
+    @Test
     public void testConnectAsync_callsListenerIfBindingDies() throws Exception {
-        mTransportClient.connectAsync(mTransportListener, "caller");
+        mTransportClient.connectAsync(mTransportConnectionListener, "caller");
 
         ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
         connection.onBindingDied(mTransportComponent);
 
         mShadowLooper.runToEndOfTasks();
-        verify(mTransportListener).onTransportBound(isNull(), eq(mTransportClient));
+        verify(mTransportConnectionListener)
+                .onTransportConnectionResult(isNull(), eq(mTransportClient));
     }
 
     @Test
     public void testConnectAsync_whenPendingConnection_callsListenersIfBindingDies()
             throws Exception {
-        mTransportClient.connectAsync(mTransportListener, "caller1");
+        mTransportClient.connectAsync(mTransportConnectionListener, "caller1");
         ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
 
-        mTransportClient.connectAsync(mTransportListener2, "caller2");
+        mTransportClient.connectAsync(mTransportConnectionListener2, "caller2");
 
         connection.onBindingDied(mTransportComponent);
 
         mShadowLooper.runToEndOfTasks();
-        verify(mTransportListener).onTransportBound(isNull(), eq(mTransportClient));
-        verify(mTransportListener2).onTransportBound(isNull(), eq(mTransportClient));
-    }*/
+        verify(mTransportConnectionListener)
+                .onTransportConnectionResult(isNull(), eq(mTransportClient));
+        verify(mTransportConnectionListener2)
+                .onTransportConnectionResult(isNull(), eq(mTransportClient));
+    }
 
     private ServiceConnection verifyBindServiceAsUserAndCaptureServiceConnection(Context context) {
         ArgumentCaptor<ServiceConnection> connectionCaptor =
diff --git a/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowContextImpl.java b/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowContextImpl.java
new file mode 100644
index 0000000..6d22073
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowContextImpl.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.testing.shadows;
+
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.UserHandle;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowContextImpl;
+
+@Implements(className = ShadowContextImpl.CLASS_NAME, inheritImplementationMethods = true)
+public class FrameworkShadowContextImpl extends ShadowContextImpl {
+    @Implementation
+    public boolean bindServiceAsUser(
+            Intent service,
+            ServiceConnection connection,
+            int flags,
+            UserHandle user) {
+        return bindService(service, connection, flags);
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java b/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowPackageManager.java
similarity index 83%
rename from services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java
rename to services/robotests/src/com/android/server/testing/shadows/FrameworkShadowPackageManager.java
index b64b59d..5cdbe7f 100644
--- a/services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java
+++ b/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowPackageManager.java
@@ -14,22 +14,18 @@
  * limitations under the License
  */
 
-package com.android.server.backup.testing;
+package com.android.server.testing.shadows;
 
 import android.app.ApplicationPackageManager;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
-
+import java.util.List;
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadows.ShadowApplicationPackageManager;
 
-import java.util.List;
-
-/**
- * Implementation of PackageManager for Robolectric which handles queryIntentServicesAsUser().
- */
+/** Extension of ShadowApplicationPackageManager */
 @Implements(value = ApplicationPackageManager.class, inheritImplementationMethods = true)
-public class ShadowPackageManagerForBackup extends ShadowApplicationPackageManager {
+public class FrameworkShadowPackageManager extends ShadowApplicationPackageManager {
     @Override
     public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
         return queryIntentServices(intent, flags);
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchingActivityPositionerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
similarity index 73%
rename from services/tests/servicestests/src/com/android/server/am/LaunchingActivityPositionerTests.java
rename to services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
index 62fa764..f741c70 100644
--- a/services/tests/servicestests/src/com/android/server/am/LaunchingActivityPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
@@ -17,55 +17,55 @@
 package com.android.server.am;
 
 import android.app.ActivityOptions;
-import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import com.android.server.am.LaunchParamsController.LaunchParams;
 import org.junit.runner.RunWith;
 import org.junit.Before;
 import org.junit.Test;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.doAnswer;
 
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_SKIP;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
 
 /**
  * Tests for exercising resizing bounds due to activity options.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.am.LaunchingActivityPositionerTests
+ *  atest FrameworksServicesTests:ActivityLaunchParamsModifierTests
  */
 @MediumTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class LaunchingActivityPositionerTests extends ActivityTestsBase {
-    private LaunchingActivityPositioner mPositioner;
+public class ActivityLaunchParamsModifierTests extends ActivityTestsBase {
+    private ActivityLaunchParamsModifier mModifier;
     private ActivityManagerService mService;
     private ActivityStack mStack;
     private TaskRecord mTask;
     private ActivityRecord mActivity;
 
-    private Rect mCurrent;
-    private Rect mResult;
+    private LaunchParams mCurrent;
+    private LaunchParams mResult;
 
     @Before
     @Override
     public void setUp() throws Exception {
         super.setUp();
         mService = createActivityManagerService();
-        mPositioner = new LaunchingActivityPositioner(mService.mStackSupervisor);
-        mCurrent = new Rect();
-        mResult = new Rect();
+        mModifier = new ActivityLaunchParamsModifier(mService.mStackSupervisor);
+        mCurrent = new LaunchParams();
+        mResult = new LaunchParams();
 
 
         mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
@@ -78,35 +78,35 @@
     @Test
     public void testSkippedInvocations() throws Exception {
         // No specified activity should be ignored
-        assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 null /*activity*/, null /*source*/, null /*options*/, mCurrent, mResult));
 
         // No specified activity options should be ignored
-        assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, null /*options*/, mCurrent, mResult));
 
         // launch bounds specified should be ignored.
         final ActivityOptions options = ActivityOptions.makeBasic();
-        assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
 
         // Non-resizeable records should be ignored
         mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
         assertFalse(mActivity.isResizeable());
-        assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
 
         // make record resizeable
         mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
         assertTrue(mActivity.isResizeable());
 
-        assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
 
         // Does not support freeform
         mService.mSupportsFreeformWindowManagement = false;
         assertFalse(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
-        assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
 
         mService.mSupportsFreeformWindowManagement = true;
@@ -114,15 +114,15 @@
         assertTrue(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
 
         // Invalid bounds
-        assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
         options.setLaunchBounds(new Rect(0, 0, -1, -1));
-        assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
 
         // Valid bounds should cause the positioner to be applied.
         options.setLaunchBounds(new Rect(0, 0, 100, 100));
-        assertEquals(RESULT_DONE, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
     }
 
@@ -136,8 +136,8 @@
         final Rect proposedBounds = new Rect(20, 30, 45, 40);
         options.setLaunchBounds(proposedBounds);
 
-        assertEquals(RESULT_DONE, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+        assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
                 mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-        assertEquals(mResult, proposedBounds);
+        assertEquals(mResult.mBounds, proposedBounds);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index ee45595..9923fa8 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -21,6 +21,10 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
@@ -32,25 +36,29 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.PauseActivityItem;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.MutableBoolean;
 
 import org.junit.runner.RunWith;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
 
 /**
  * Tests for the {@link ActivityRecord} class.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.am.ActivityRecordTests
+ *  atest FrameworksServicesTests:com.android.server.am.ActivityRecordTests
  */
 @MediumTest
 @Presubmit
@@ -101,6 +109,32 @@
     }
 
     @Test
+    public void testPausingWhenVisibleFromStopped() throws Exception {
+        final MutableBoolean pauseFound = new MutableBoolean(false);
+        doAnswer((InvocationOnMock invocationOnMock) -> {
+            final ClientTransaction transaction = invocationOnMock.getArgument(0);
+            if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
+                pauseFound.value = true;
+            }
+            return null;
+        }).when(mActivity.app.thread).scheduleTransaction(any());
+        mActivity.state = STOPPED;
+
+        mActivity.makeVisibleIfNeeded(null /* starting */);
+
+        assertEquals(mActivity.state, PAUSING);
+
+        assertTrue(pauseFound.value);
+
+        // Make sure that the state does not change for current non-stopping states.
+        mActivity.state = INITIALIZING;
+
+        mActivity.makeVisibleIfNeeded(null /* starting */);
+
+        assertEquals(mActivity.state, INITIALIZING);
+    }
+
+    @Test
     public void testPositionLimitedAspectRatioNavBarBottom() throws Exception {
         verifyPositionWithLimitedAspectRatio(NAV_BAR_BOTTOM, new Rect(0, 0, 1000, 2000), 1.5f,
                 new Rect(0, 0, 1000, 1500));
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index d74d994..96bf49b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -32,6 +32,7 @@
 
 import org.mockito.invocation.InvocationOnMock;
 
+import android.app.IApplicationThread;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -177,6 +178,10 @@
                 mTaskRecord.addActivityToTop(activity);
             }
 
+            activity.setProcess(new ProcessRecord(null, mService.mContext.getApplicationInfo(),
+                    "name", 12345));
+            activity.app.thread = mock(IApplicationThread.class);
+
             return activity;
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/am/ClientLifecycleManagerTests.java b/services/tests/servicestests/src/com/android/server/am/ClientLifecycleManagerTests.java
new file mode 100644
index 0000000..ef6d5e8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ClientLifecycleManagerTests.java
@@ -0,0 +1,44 @@
+package com.android.server.am;
+
+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.app.IApplicationThread;
+import android.app.servertransaction.ClientTransaction;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class ClientLifecycleManagerTests {
+
+    @Test
+    public void testScheduleAndRecycleBinderClientTransaction() throws Exception {
+        ClientTransaction item = spy(ClientTransaction.obtain(mock(IApplicationThread.class),
+                new Binder()));
+
+        ClientLifecycleManager clientLifecycleManager = new ClientLifecycleManager();
+        clientLifecycleManager.scheduleTransaction(item);
+
+        verify(item, times(1)).recycle();
+    }
+
+    @Test
+    public void testScheduleNoRecycleNonBinderClientTransaction() throws Exception {
+        ClientTransaction item = spy(ClientTransaction.obtain(mock(IApplicationThread.Stub.class),
+                new Binder()));
+
+        ClientLifecycleManager clientLifecycleManager = new ClientLifecycleManager();
+        clientLifecycleManager.scheduleTransaction(item);
+
+        verify(item, times(0)).recycle();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java b/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
new file mode 100644
index 0000000..161c287
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import android.app.ActivityOptions;
+import android.content.pm.ActivityInfo.WindowLayout;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.am.LaunchParamsController.LaunchParams;
+import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+/**
+ * Tests for exercising {@link LaunchParamsController}.
+ *
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:LaunchParamsControllerTests
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class LaunchParamsControllerTests extends ActivityTestsBase {
+    private ActivityManagerService mService;
+    private LaunchParamsController mController;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mService = createActivityManagerService();
+        mController = new LaunchParamsController(mService);
+    }
+
+    /**
+     * Makes sure positioners get values passed to controller.
+     */
+    @Test
+    public void testArgumentPropagation() {
+        final LaunchParamsModifier
+                positioner = mock(LaunchParamsModifier.class);
+        mController.registerModifier(positioner);
+
+        final ActivityRecord record = new ActivityBuilder(mService).build();
+        final ActivityRecord source = new ActivityBuilder(mService).build();
+        final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
+        final ActivityOptions options = mock(ActivityOptions.class);
+
+        mController.calculate(record.getTask(), layout, record, source, options,
+                new LaunchParams());
+        verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record),
+                eq(source), eq(options), any(), any());
+    }
+
+    /**
+     * Ensures positioners further down the chain are not called when RESULT_DONE is returned.
+     */
+    @Test
+    public void testEarlyExit() {
+        final LaunchParamsModifier
+                ignoredPositioner = mock(LaunchParamsModifier.class);
+        final LaunchParamsModifier earlyExitPositioner =
+                (task, layout, activity, source, options, currentParams, outParams) -> RESULT_DONE;
+
+        mController.registerModifier(ignoredPositioner);
+        mController.registerModifier(earlyExitPositioner);
+
+        mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
+                null /*source*/, null /*options*/, new LaunchParams());
+        verify(ignoredPositioner, never()).onCalculate(any(), any(), any(), any(), any(),
+                any(), any());
+    }
+
+    /**
+     * Ensures that positioners are called in the correct order.
+     */
+    @Test
+    public void testRegistration() {
+        LaunchParamsModifier earlyExitPositioner =
+                new InstrumentedPositioner(RESULT_DONE, new LaunchParams());
+
+        final LaunchParamsModifier firstPositioner = spy(earlyExitPositioner);
+
+        mController.registerModifier(firstPositioner);
+
+        mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
+                null /*source*/, null /*options*/, new LaunchParams());
+        verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(),
+                any());
+
+        final LaunchParamsModifier secondPositioner = spy(earlyExitPositioner);
+
+        mController.registerModifier(secondPositioner);
+
+        mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
+                null /*source*/, null /*options*/, new LaunchParams());
+        verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(),
+                any());
+        verify(secondPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(),
+                any());
+    }
+
+    /**
+     * Makes sure positioners further down the registration chain are called.
+     */
+    @Test
+    public void testPassThrough() {
+        final LaunchParamsModifier
+                positioner1 = mock(LaunchParamsModifier.class);
+        final LaunchParams params = new LaunchParams();
+        params.mWindowingMode = WINDOWING_MODE_FREEFORM;
+        params.mBounds.set(0, 0, 30, 20);
+        params.mPreferredDisplayId = 3;
+
+        final InstrumentedPositioner positioner2 = new InstrumentedPositioner(RESULT_CONTINUE,
+                params);
+
+        mController.registerModifier(positioner1);
+        mController.registerModifier(positioner2);
+
+        mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/,
+                null /*options*/, new LaunchParams());
+
+        verify(positioner1, times(1)).onCalculate(any(), any(), any(), any(), any(),
+                eq(positioner2.getLaunchParams()), any());
+    }
+
+    /**
+     * Ensures skipped results are not propagated.
+     */
+    @Test
+    public void testSkip() {
+        final LaunchParams params1 = new LaunchParams();
+        params1.mBounds.set(0, 0, 10, 10);
+        final InstrumentedPositioner positioner1 = new InstrumentedPositioner(RESULT_SKIP, params1);
+
+        final LaunchParams params2 = new LaunchParams();
+        params2.mBounds.set(0, 0, 20, 30);
+        final InstrumentedPositioner positioner2 =
+                new InstrumentedPositioner(RESULT_CONTINUE, params2);
+
+        mController.registerModifier(positioner1);
+        mController.registerModifier(positioner2);
+
+        final LaunchParams
+                result = new LaunchParams();
+
+        mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/,
+                null /*options*/, result);
+
+        assertEquals(result, positioner2.getLaunchParams());
+    }
+
+    /**
+     * Ensures that {@link LaunchParamsModifier} requests specifying display id during
+     * layout are honored.
+     */
+    @Test
+    public void testLayoutTaskPreferredDisplayChange() {
+        final LaunchParams params = new LaunchParams();
+        params.mPreferredDisplayId = 2;
+        final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
+        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+
+        mController.registerModifier(positioner);
+
+        doNothing().when(mService).moveStackToDisplay(anyInt(), anyInt());
+        mController.layoutTask(task, null /* windowLayout */);
+        verify(mService, times(1)).moveStackToDisplay(eq(task.getStackId()),
+                eq(params.mPreferredDisplayId));
+    }
+
+    /**
+     * Ensures that {@link LaunchParamsModifier} requests specifying windowingMode during
+     * layout are honored.
+     */
+    @Test
+    public void testLayoutTaskWindowingModeChange() {
+        final LaunchParams params = new LaunchParams();
+        final int windowingMode = WINDOWING_MODE_FREEFORM;
+        params.mWindowingMode = windowingMode;
+        final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
+        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+
+        mController.registerModifier(positioner);
+
+        final int beforeWindowMode = task.getStack().getWindowingMode();
+        assertNotEquals(beforeWindowMode, windowingMode);
+
+        mController.layoutTask(task, null /* windowLayout */);
+
+        final int afterWindowMode = task.getStack().getWindowingMode();
+        assertEquals(afterWindowMode, windowingMode);
+    }
+
+    public static class InstrumentedPositioner implements
+            LaunchParamsModifier {
+
+        final private int mReturnVal;
+        final private LaunchParams mParams;
+
+        InstrumentedPositioner(int returnVal, LaunchParams params) {
+            mReturnVal = returnVal;
+            mParams = params;
+        }
+
+        @Override
+        public int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+                   ActivityRecord source, ActivityOptions options,
+                   LaunchParams currentParams, LaunchParams outParams) {
+            outParams.set(mParams);
+            return mReturnVal;
+        }
+
+        LaunchParams getLaunchParams() {
+            return mParams;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchingBoundsControllerTests.java b/services/tests/servicestests/src/com/android/server/am/LaunchingBoundsControllerTests.java
deleted file mode 100644
index 0715174..0000000
--- a/services/tests/servicestests/src/com/android/server/am/LaunchingBoundsControllerTests.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.am;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ActivityInfo.WindowLayout;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.runner.RunWith;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_DONE;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_CONTINUE;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_SKIP;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Tests for exercising {@link LaunchingBoundsController}.
- *
- * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.am.LaunchingBoundsControllerTests
- */
-@MediumTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class LaunchingBoundsControllerTests extends ActivityTestsBase {
-    private LaunchingBoundsController mController;
-
-    @Before
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mController = new LaunchingBoundsController();
-    }
-
-    /**
-     * Makes sure positioners get values passed to controller.
-     */
-    @Test
-    public void testArgumentPropagation() {
-        final ActivityManagerService service = createActivityManagerService();
-        final LaunchingBoundsPositioner positioner = mock(LaunchingBoundsPositioner.class);
-        mController.registerPositioner(positioner);
-
-        final ActivityRecord record = new ActivityBuilder(service).build();
-        final ActivityRecord source = new ActivityBuilder(service).build();
-        final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
-        final ActivityOptions options = mock(ActivityOptions.class);
-
-        mController.calculateBounds(record.getTask(), layout, record, source, options, new Rect());
-        verify(positioner, times(1)).onCalculateBounds(eq(record.getTask()), eq(layout), eq(record),
-                eq(source), eq(options), any(), any());
-    }
-
-    /**
-     * Ensures positioners further down the chain are not called when RESULT_DONE is returned.
-     */
-    @Test
-    public void testEarlyExit() {
-        final LaunchingBoundsPositioner ignoredPositioner = mock(LaunchingBoundsPositioner.class);
-        final LaunchingBoundsPositioner earlyExitPositioner =
-                (task, layout, activity, source, options, current, result) -> RESULT_DONE;
-
-        mController.registerPositioner(ignoredPositioner);
-        mController.registerPositioner(earlyExitPositioner);
-
-        mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
-                null /*source*/, null /*options*/, new Rect());
-        verify(ignoredPositioner, never()).onCalculateBounds(any(), any(), any(), any(), any(),
-                any(), any());
-    }
-
-    /**
-     * Ensures that positioners are called in the correct order.
-     */
-    @Test
-    public void testRegistration() {
-        LaunchingBoundsPositioner earlyExitPositioner =
-                new InstrumentedPositioner(RESULT_DONE, new Rect());
-
-        final LaunchingBoundsPositioner firstPositioner = spy(earlyExitPositioner);
-
-        mController.registerPositioner(firstPositioner);
-
-        mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
-                null /*source*/, null /*options*/, new Rect());
-        verify(firstPositioner, times(1)).onCalculateBounds(any(), any(), any(), any(), any(),
-                any(), any());
-
-        final LaunchingBoundsPositioner secondPositioner = spy(earlyExitPositioner);
-
-        mController.registerPositioner(secondPositioner);
-
-        mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
-                null /*source*/, null /*options*/, new Rect());
-        verify(firstPositioner, times(1)).onCalculateBounds(any(), any(), any(), any(), any(),
-                any(), any());
-        verify(secondPositioner, times(1)).onCalculateBounds(any(), any(), any(), any(), any(),
-                any(), any());
-    }
-
-    /**
-     * Makes sure positioners further down the registration chain are called.
-     */
-    @Test
-    public void testPassThrough() {
-        final LaunchingBoundsPositioner positioner1 = mock(LaunchingBoundsPositioner.class);
-        final InstrumentedPositioner positioner2 = new InstrumentedPositioner(RESULT_CONTINUE,
-                new Rect (0, 0, 30, 20));
-
-        mController.registerPositioner(positioner1);
-        mController.registerPositioner(positioner2);
-
-        mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
-                null /*source*/, null /*options*/, new Rect());
-
-        verify(positioner1, times(1)).onCalculateBounds(any(), any(), any(), any(), any(),
-                eq(positioner2.getLaunchBounds()), any());
-    }
-
-    /**
-     * Ensures skipped results are not propagated.
-     */
-    @Test
-    public void testSkip() {
-        final InstrumentedPositioner positioner1 =
-                new InstrumentedPositioner(RESULT_SKIP, new Rect(0, 0, 10, 10));
-
-
-        final InstrumentedPositioner positioner2 =
-                new InstrumentedPositioner(RESULT_CONTINUE, new Rect(0, 0, 20, 30));
-
-        mController.registerPositioner(positioner1);
-        mController.registerPositioner(positioner2);
-
-        final Rect resultBounds = new Rect();
-
-        mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
-                null /*source*/, null /*options*/, resultBounds);
-
-        assertEquals(resultBounds, positioner2.getLaunchBounds());
-    }
-
-    public static class InstrumentedPositioner implements LaunchingBoundsPositioner {
-        private int mReturnVal;
-        private Rect mBounds;
-        InstrumentedPositioner(int returnVal, Rect bounds) {
-            mReturnVal = returnVal;
-            mBounds = bounds;
-        }
-
-        @Override
-        public int onCalculateBounds(TaskRecord task, ActivityInfo.WindowLayout layout,
-                ActivityRecord activity, ActivityRecord source,
-                ActivityOptions options, Rect current, Rect result) {
-            result.set(mBounds);
-            return mReturnVal;
-        }
-
-        Rect getLaunchBounds() {
-            return mBounds;
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
similarity index 81%
rename from services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java
rename to services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
index 13daf3e..3d323f0 100644
--- a/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
@@ -23,6 +23,7 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import android.view.Gravity;
+
 import org.junit.runner.RunWith;
 import org.junit.Before;
 import org.junit.Test;
@@ -32,7 +33,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
 
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
@@ -42,15 +43,15 @@
 
 
 /**
- * Tests for exercising resizing bounds.
+ * Tests for exercising resizing task bounds.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.am.LaunchingTaskPositionerTests
+ *  atest FrameworksServicesTests:TaskLaunchParamsModifierTests
  */
 @MediumTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class LaunchingTaskPositionerTests extends ActivityTestsBase {
+public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
     private final static int STACK_WIDTH = 100;
     private final static int STACK_HEIGHT = 200;
 
@@ -60,10 +61,10 @@
     private ActivityStack mStack;
     private TaskRecord mTask;
 
-    private LaunchingTaskPositioner mPositioner;
+    private TaskLaunchParamsModifier mPositioner;
 
-    private Rect mCurrent;
-    private Rect mResult;
+    private LaunchParamsController.LaunchParams mCurrent;
+    private LaunchParamsController.LaunchParams mResult;
 
     @Before
     @Override
@@ -79,10 +80,10 @@
         // dimensions on resize.
         mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
 
-        mPositioner = new LaunchingTaskPositioner();
+        mPositioner = new TaskLaunchParamsModifier();
 
-        mResult = new Rect();
-        mCurrent = new Rect();
+        mResult = new LaunchParamsController.LaunchParams();
+        mCurrent = new LaunchParamsController.LaunchParams();
     }
 
     /**
@@ -103,9 +104,9 @@
      */
     @Test
     public void testLaunchNoWindowLayout() throws Exception {
-        assertEquals(RESULT_CONTINUE, mPositioner.onCalculateBounds(mTask, null /*layout*/,
+        assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask, null /*layout*/,
                 null /*record*/, null /*source*/, null /*options*/, mCurrent, mResult));
-        assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult);
+        assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult.mBounds);
     }
 
     /**
@@ -115,10 +116,10 @@
      */
     @Test
     public void testlaunchEmptyWindowLayout() throws Exception {
-        assertEquals(RESULT_CONTINUE, mPositioner.onCalculateBounds(mTask,
+        assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
                 new WindowLayout(0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0), null /*activity*/,
                 null /*source*/, null /*options*/, mCurrent, mResult));
-        assertEquals(mResult, getDefaultBounds(Gravity.NO_GRAVITY));
+        assertEquals(mResult.mBounds, getDefaultBounds(Gravity.NO_GRAVITY));
     }
 
     /**
@@ -148,13 +149,13 @@
 
     private void testGravity(int gravity) {
         try {
-            assertEquals(RESULT_CONTINUE, mPositioner.onCalculateBounds(mTask,
+            assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
                     new WindowLayout(0, 0, 0, 0, gravity, 0, 0), null /*activity*/,
                     null /*source*/, null /*options*/, mCurrent, mResult));
-            assertEquals(mResult, getDefaultBounds(gravity));
+            assertEquals(mResult.mBounds, getDefaultBounds(gravity));
         } finally {
-            mCurrent.setEmpty();
-            mResult.setEmpty();
+            mCurrent.reset();
+            mResult.reset();
         }
     }
 
@@ -178,7 +179,7 @@
         final WindowLayout layout = new WindowLayout(0, 0, 0, 0, gravity, 0, 0);
 
         // layout first task
-        mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(mTask, layout);
+        mService.mStackSupervisor.getLaunchParamsController().layoutTask(mTask, layout);
 
         // Second task will be laid out on top of the first so starting bounds is the same.
         final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
@@ -196,25 +197,25 @@
 
             // layout second task
             assertEquals(RESULT_CONTINUE,
-                    mPositioner.onCalculateBounds(secondTask, layout, null /*activity*/,
+                    mPositioner.onCalculate(secondTask, layout, null /*activity*/,
                             null /*source*/, null /*options*/, mCurrent, mResult));
 
             if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
                     || (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
                     == (Gravity.BOTTOM | Gravity.RIGHT)) {
-                expectedBounds.offset(-LaunchingTaskPositioner.getHorizontalStep(
+                expectedBounds.offset(-TaskLaunchParamsModifier.getHorizontalStep(
                         mStack.getOverrideBounds()), 0);
             } else if ((gravity & Gravity.TOP) == Gravity.TOP
                     || (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
                 expectedBounds.offset(
-                        LaunchingTaskPositioner.getHorizontalStep(mStack.getOverrideBounds()), 0);
+                        TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()), 0);
             } else {
                 expectedBounds.offset(
-                        LaunchingTaskPositioner.getHorizontalStep(mStack.getOverrideBounds()),
-                        LaunchingTaskPositioner.getVerticalStep(mStack.getOverrideBounds()));
+                        TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()),
+                        TaskLaunchParamsModifier.getVerticalStep(mStack.getOverrideBounds()));
             }
 
-            assertEquals(mResult, expectedBounds);
+            assertEquals(mResult.mBounds, expectedBounds);
         } finally {
             // Remove task and activity to prevent influencing future tests
             if (activity != null) {
@@ -232,9 +233,9 @@
         bounds.set(mStack.getOverrideBounds());
 
         final int verticalInset =
-                LaunchingTaskPositioner.getFreeformStartTop(mStack.getOverrideBounds());
+                TaskLaunchParamsModifier.getFreeformStartTop(mStack.getOverrideBounds());
         final int horizontalInset =
-                LaunchingTaskPositioner.getFreeformStartLeft(mStack.getOverrideBounds());
+                TaskLaunchParamsModifier.getFreeformStartLeft(mStack.getOverrideBounds());
 
         bounds.inset(horizontalInset, verticalInset);
 
diff --git a/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
index 766d30d..7b4441a 100644
--- a/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -96,7 +96,7 @@
         createBackupManagerService();
 
         verify(mTransportManager)
-                .setTransportBoundListener(any(TransportManager.TransportBoundListener.class));
+                .setOnTransportRegisteredListener(any());
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 0650acb..5134f52 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -15,11 +15,13 @@
  */
 package com.android.server.devicepolicy;
 
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.IActivityManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.backup.IBackupManager;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
@@ -152,6 +154,11 @@
         }
 
         @Override
+        UsageStatsManagerInternal getUsageStatsManagerInternal() {
+            return services.usageStatsManagerInternal;
+        }
+
+        @Override
         PackageManagerInternal getPackageManagerInternal() {
             return services.packageManagerInternal;
         }
@@ -182,6 +189,11 @@
         }
 
         @Override
+        ActivityManagerInternal getActivityManagerInternal() {
+            return services.activityManagerInternal;
+        }
+
+        @Override
         IPackageManager getIPackageManager() {
             return services.ipackageManager;
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 58ac7d2..1df0ff2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -44,6 +44,7 @@
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 import static org.mockito.hamcrest.MockitoHamcrest.argThat;
@@ -86,10 +87,12 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.devicepolicy.DevicePolicyManagerService.RestrictionsListener;
 import com.android.server.pm.UserRestrictionsUtils;
 
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
+import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
@@ -182,6 +185,7 @@
 
         initializeDpms();
 
+        Mockito.reset(getServices().usageStatsManagerInternal);
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
         setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
         setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
@@ -207,6 +211,7 @@
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
 
         dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
+        dpms.handleStart();
         dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
         dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -278,6 +283,32 @@
         assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
     }
 
+    public void testHandleStart() throws Exception {
+        // Device owner in SYSTEM_USER
+        setDeviceOwner();
+        // Profile owner in CALLER_USER_HANDLE
+        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
+        setAsProfileOwner(admin2);
+        // Active admin in CALLER_USER_HANDLE
+        final int ANOTHER_UID = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, 1306);
+        setUpPackageManagerForFakeAdmin(adminAnotherPackage, ANOTHER_UID, admin2);
+        dpm.setActiveAdmin(adminAnotherPackage, /* replace =*/ false,
+                DpmMockContext.CALLER_USER_HANDLE);
+        assertTrue(dpm.isAdminActiveAsUser(adminAnotherPackage,
+                DpmMockContext.CALLER_USER_HANDLE));
+
+        initializeDpms();
+
+        // Verify
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                MockUtils.checkAdminApps(admin1.getPackageName()),
+                eq(UserHandle.USER_SYSTEM));
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                MockUtils.checkAdminApps(admin2.getPackageName(),
+                        adminAnotherPackage.getPackageName()),
+                eq(DpmMockContext.CALLER_USER_HANDLE));
+    }
+
     /**
      * Caller doesn't have proper permissions.
      */
@@ -330,6 +361,9 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 anyString());
 
+        verify(getServices().usageStatsManagerInternal).onActiveAdminAdded(
+                admin1.getPackageName(), DpmMockContext.CALLER_USER_HANDLE);
+
         // TODO Verify other calls too.
 
         // Make sure it's active admin1.
@@ -369,6 +403,11 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 anyString());
 
+        // times(2) because it was previously called for admin1 which is in the same package
+        // as admin2.
+        verify(getServices().usageStatsManagerInternal, times(2)).onActiveAdminAdded(
+                admin2.getPackageName(), DpmMockContext.CALLER_USER_HANDLE);
+
         // 4. Add the same admin1 again without replace, which should throw.
         assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null,
                 () -> dpm.setActiveAdmin(admin1, /* replace =*/ false));
@@ -384,6 +423,10 @@
         assertEquals(admin1, admins.get(0));
         assertEquals(admin2, admins.get(1));
 
+        // There shouldn't be any callback to UsageStatsManagerInternal when the admin is being
+        // replaced
+        verifyNoMoreInteractions(getServices().usageStatsManagerInternal);
+
         // Another user has no admins.
         mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
 
@@ -516,6 +559,8 @@
                 () -> dpm.removeActiveAdmin(admin1));
 
         assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+        verify(getServices().usageStatsManagerInternal, times(0)).setActiveAdminApps(
+                null, DpmMockContext.CALLER_USER_HANDLE);
 
         // 2. User unlocked.
         when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
@@ -523,6 +568,8 @@
 
         dpm.removeActiveAdmin(admin1);
         assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                null, DpmMockContext.CALLER_USER_HANDLE);
     }
 
     /**
@@ -547,6 +594,8 @@
 
         dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
         assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                null, DpmMockContext.CALLER_USER_HANDLE);
 
         // TODO DO Still can't be removed in this case.
     }
@@ -588,6 +637,8 @@
                 isNull(Bundle.class));
 
         assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                null, DpmMockContext.CALLER_USER_HANDLE);
 
         // Again broadcast from saveSettingsLocked().
         verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
@@ -598,6 +649,86 @@
         // TODO Check other internal calls.
     }
 
+    public void testRemoveActiveAdmin_multipleAdminsInUser() {
+        // Need MANAGE_DEVICE_ADMINS for setActiveAdmin.  We'll remove it later.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin1.
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+        assertTrue(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Add admin2.
+        dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+        assertTrue(dpm.isAdminActive(admin2));
+        assertFalse(dpm.isRemovingAdmin(admin2, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Broadcast from saveSettingsLocked().
+        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+        // Remove.  No permissions, but same user, so it'll work.
+        mContext.callerPermissions.clear();
+        dpm.removeActiveAdmin(admin1);
+
+        verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+                isNull(String.class),
+                any(BroadcastReceiver.class),
+                eq(dpms.mHandler),
+                eq(Activity.RESULT_OK),
+                isNull(String.class),
+                isNull(Bundle.class));
+
+        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                MockUtils.checkAdminApps(admin2.getPackageName()),
+                eq(DpmMockContext.CALLER_USER_HANDLE));
+
+        // Again broadcast from saveSettingsLocked().
+        verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
+     */
+    public void testForceRemoveActiveAdmin() throws Exception {
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin.
+        setupPackageInPackageManager(admin1.getPackageName(),
+                /* userId= */ DpmMockContext.CALLER_USER_HANDLE,
+                /* appId= */ 10138,
+                /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        assertTrue(dpm.isAdminActive(admin1));
+
+        // Calling from a non-shell uid should fail with a SecurityException
+        mContext.binder.callingUid = 123456;
+        assertExpectException(SecurityException.class,
+                /* messageRegex =*/ "Non-shell user attempted to call",
+                () -> dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        mContext.binder.callingUid = Process.SHELL_UID;
+        dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+        mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+        // Verify
+        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                null, DpmMockContext.CALLER_USER_HANDLE);
+    }
+
     /**
      * Test for: @{link DevicePolicyManager#setActivePasswordState}
      *
@@ -954,6 +1085,9 @@
                 eq(null),
                 eq(true), eq(CAMERA_NOT_DISABLED));
 
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                null, UserHandle.USER_SYSTEM);
+
         assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));
 
         // ACTION_DEVICE_OWNER_CHANGED should be sent twice, once for setting the device owner
@@ -1044,6 +1178,8 @@
         // Check
         assertFalse(dpm.isProfileOwnerApp(admin1.getPackageName()));
         assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                null, DpmMockContext.CALLER_USER_HANDLE);
     }
 
     public void testSetProfileOwner_failures() throws Exception {
@@ -3885,6 +4021,8 @@
         dpm.setPasswordMinimumNumeric(admin1, 1);
         dpm.setPasswordMinimumSymbols(admin1, 0);
 
+        reset(mContext.spiedContext);
+
         PasswordMetrics passwordMetricsNoSymbols = new PasswordMetrics(
                 DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
                 8, 2,
@@ -3934,9 +4072,16 @@
         dpm.setActivePasswordState(passwordMetrics, userHandle);
         dpm.reportPasswordChanged(userHandle);
 
+        // Drain ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED broadcasts as part of
+        // reportPasswordChanged()
+        verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(userHandle));
+
         final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
         intent.setComponent(admin1);
-        intent.putExtra(Intent.EXTRA_USER, UserHandle.of(mContext.binder.callingUid));
+        intent.putExtra(Intent.EXTRA_USER, UserHandle.of(userHandle));
 
         verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                 MockUtils.checkIntent(intent),
@@ -4347,6 +4492,45 @@
         verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null, caller);
     }
 
+    public void testDisallowSharingIntoProfileSetRestriction() {
+        Bundle restriction = new Bundle();
+        restriction.putBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, true);
+
+        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+        RestrictionsListener listener = new RestrictionsListener(mContext);
+        listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, restriction,
+                new Bundle());
+        verifyDataSharingChangedBroadcast();
+    }
+
+    public void testDisallowSharingIntoProfileClearRestriction() {
+        Bundle restriction = new Bundle();
+        restriction.putBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, true);
+
+        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+        RestrictionsListener listener = new RestrictionsListener(mContext);
+        listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, new Bundle(),
+                restriction);
+        verifyDataSharingChangedBroadcast();
+    }
+
+    public void testDisallowSharingIntoProfileUnchanged() {
+        RestrictionsListener listener = new RestrictionsListener(mContext);
+        listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, new Bundle(),
+                new Bundle());
+        verify(mContext.spiedContext, never()).sendBroadcastAsUser(any(), any());
+    }
+
+    private void verifyDataSharingChangedBroadcast() {
+        Intent expectedIntent = new Intent(
+                DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_CHANGED);
+        expectedIntent.setPackage("com.android.managedprovisioning");
+        expectedIntent.putExtra(Intent.EXTRA_USER_ID, DpmMockContext.CALLER_USER_HANDLE);
+        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+                MockUtils.checkIntent(expectedIntent),
+                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+    }
+
     private void verifyCanGetOwnerInstalledCaCerts(
             final ComponentName caller, final DpmMockContext callerContext) throws Exception {
         final String alias = "cert";
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 4232c44..268d424 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -25,10 +25,12 @@
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.IActivityManager;
 import android.app.NotificationManager;
 import android.app.backup.IBackupManager;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -73,6 +75,7 @@
     public final SystemPropertiesForMock systemProperties;
     public final UserManager userManager;
     public final UserManagerInternal userManagerInternal;
+    public final UsageStatsManagerInternal usageStatsManagerInternal;
     public final PackageManagerInternal packageManagerInternal;
     public final UserManagerForMock userManagerForMock;
     public final PowerManagerForMock powerManager;
@@ -82,6 +85,7 @@
     public final IIpConnectivityMetrics iipConnectivityMetrics;
     public final IWindowManager iwindowManager;
     public final IActivityManager iactivityManager;
+    public ActivityManagerInternal activityManagerInternal;
     public final IPackageManager ipackageManager;
     public final IBackupManager ibackupManager;
     public final IAudioService iaudioService;
@@ -108,6 +112,7 @@
         systemProperties = mock(SystemPropertiesForMock.class);
         userManager = mock(UserManager.class);
         userManagerInternal = mock(UserManagerInternal.class);
+        usageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
         userManagerForMock = mock(UserManagerForMock.class);
         packageManagerInternal = mock(PackageManagerInternal.class);
         powerManager = mock(PowerManagerForMock.class);
@@ -117,6 +122,7 @@
         iipConnectivityMetrics = mock(IIpConnectivityMetrics.class);
         iwindowManager = mock(IWindowManager.class);
         iactivityManager = mock(IActivityManager.class);
+        activityManagerInternal = mock(ActivityManagerInternal.class);
         ipackageManager = mock(IPackageManager.class);
         ibackupManager = mock(IBackupManager.class);
         iaudioService = mock(IAudioService.class);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index e43786c..dec962e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -24,13 +24,16 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.util.ArraySet;
 
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
-import org.mockito.Mockito;
 import org.mockito.hamcrest.MockitoHamcrest;
 
+import java.util.Arrays;
+import java.util.Set;
+
 public class MockUtils {
     private MockUtils() {
     }
@@ -88,7 +91,8 @@
             @Override
             public boolean matches(Object item) {
                 if (item == null) return false;
-                return intent.filterEquals((Intent) item);
+                if (!intent.filterEquals((Intent) item)) return false;
+                return intent.getExtras().kindofEquals(((Intent) item).getExtras());
             }
             @Override
             public void describeTo(Description description) {
@@ -115,6 +119,30 @@
         return MockitoHamcrest.argThat(m);
     }
 
+    public static Set<String> checkAdminApps(String... adminApps) {
+        final Matcher<Set<String>> m = new BaseMatcher<Set<String>>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) return false;
+                final Set<String> actualAdminApps = (Set<String>) item;
+                if (adminApps.length != actualAdminApps.size()) {
+                    return false;
+                }
+                final Set<String> copyOfAdmins = new ArraySet<>(actualAdminApps);
+                for (String adminApp : adminApps) {
+                    copyOfAdmins.remove(adminApp);
+                }
+                return copyOfAdmins.isEmpty();
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Admin apps=" + Arrays.toString(adminApps));
+            }
+        };
+        return MockitoHamcrest.argThat(m);
+    }
+
     private static String getRestrictionsAsString(Bundle b) {
         final StringBuilder sb = new StringBuilder();
         sb.append("[");
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index 08edd52..edc7d74 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -447,21 +447,24 @@
     @Test
     public void testParcelUnParcel() {
         Parcel parcel = Parcel.obtain();
-        BrightnessChangeEvent event = new BrightnessChangeEvent();
-        event.brightness = 23f;
-        event.timeStamp = 345L;
-        event.packageName = "com.example";
-        event.userId = 12;
-        event.luxValues = new float[2];
-        event.luxValues[0] = 3000.0f;
-        event.luxValues[1] = 4000.0f;
-        event.luxTimestamps = new long[2];
-        event.luxTimestamps[0] = 325L;
-        event.luxTimestamps[1] = 315L;
-        event.batteryLevel = 0.7f;
-        event.nightMode = false;
-        event.colorTemperature = 345;
-        event.lastBrightness = 50f;
+        BrightnessChangeEvent.Builder builder = new BrightnessChangeEvent.Builder();
+        builder.setBrightness(23f);
+        builder.setTimeStamp(345L);
+        builder.setPackageName("com.example");
+        builder.setUserId(12);
+        float[] luxValues = new float[2];
+        luxValues[0] = 3000.0f;
+        luxValues[1] = 4000.0f;
+        builder.setLuxValues(luxValues);
+        long[] luxTimestamps = new long[2];
+        luxTimestamps[0] = 325L;
+        luxTimestamps[1] = 315L;
+        builder.setLuxTimestamps(luxTimestamps);
+        builder.setBatteryLevel(0.7f);
+        builder.setNightMode(false);
+        builder.setColorTemperature(345);
+        builder.setLastBrightness(50f);
+        BrightnessChangeEvent event = builder.build();
 
         event.writeToParcel(parcel, 0);
         byte[] parceled = parcel.marshall();
@@ -485,7 +488,8 @@
         assertEquals(event.lastBrightness, event2.lastBrightness, FLOAT_DELTA);
 
         parcel = Parcel.obtain();
-        event.batteryLevel = Float.NaN;
+        builder.setBatteryLevel(Float.NaN);
+        event = builder.build();
         event.writeToParcel(parcel, 0);
         parceled = parcel.marshall();
         parcel.recycle();
diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
index 467b47a..14b118e 100644
--- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
@@ -37,6 +37,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -50,7 +51,6 @@
 import org.junit.runner.RunWith;
 
 /**
- * TODO: Also add a test for temp power whitelist
  * Tests that background restrictions on jobs work as expected.
  * This test requires test-apps/JobTestApp to be installed on the device.
  * To run this test from root of checkout:
@@ -144,15 +144,29 @@
                 awaitJobStop(DEFAULT_WAIT_TIMEOUT));
     }
 
+    @Test
+    public void testFeatureFlag() throws Exception {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.FORCED_APP_STANDBY_ENABLED, 0);
+        scheduleAndAssertJobStarted();
+        setAppOpsModeAllowed(false);
+        mIActivityManager.makePackageIdle(TEST_APP_PACKAGE, UserHandle.USER_CURRENT);
+        assertFalse("Job stopped even when feature flag was disabled",
+                awaitJobStop(DEFAULT_WAIT_TIMEOUT));
+    }
+
     @After
     public void tearDown() throws Exception {
-        Intent cancelJobsIntent = new Intent(TestJobActivity.ACTION_CANCEL_JOBS);
+        final Intent cancelJobsIntent = new Intent(TestJobActivity.ACTION_CANCEL_JOBS);
         cancelJobsIntent.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY));
         cancelJobsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         mContext.startActivity(cancelJobsIntent);
         mContext.unregisterReceiver(mJobStateChangeReceiver);
+        Thread.sleep(500); // To avoid race with register in the next setUp
         setAppOpsModeAllowed(true);
         setPowerWhiteListed(false);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.FORCED_APP_STANDBY_ENABLED, 1);
     }
 
     private void setPowerWhiteListed(boolean whitelist) throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 1895e15..9eb42e9 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -16,9 +16,11 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import static android.security.recoverablekeystore.KeyStoreRecoveryMetadata.TYPE_PASSWORD;
-import static android.security.recoverablekeystore.KeyStoreRecoveryMetadata.TYPE_PATTERN;
-import static android.security.recoverablekeystore.KeyStoreRecoveryMetadata.TYPE_PIN;
+import static android.security.keystore.RecoveryMetadata.TYPE_LOCKSCREEN;
+
+import static android.security.keystore.RecoveryMetadata.TYPE_PASSWORD;
+import static android.security.keystore.RecoveryMetadata.TYPE_PATTERN;
+import static android.security.keystore.RecoveryMetadata.TYPE_PIN;
 
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
@@ -38,9 +40,9 @@
 import android.security.keystore.AndroidKeyStoreSecretKey;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
-import android.security.recoverablekeystore.KeyDerivationParameters;
-import android.security.recoverablekeystore.KeyEntryRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryData;
+import android.security.keystore.KeyDerivationParams;
+import android.security.keystore.EntryRecoveryData;
+import android.security.keystore.RecoveryData;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -75,7 +77,8 @@
     private static final int TEST_USER_ID = 1000;
     private static final int TEST_RECOVERY_AGENT_UID = 10009;
     private static final int TEST_RECOVERY_AGENT_UID2 = 10010;
-    private static final long TEST_DEVICE_ID = 13295035643L;
+    private static final byte[] TEST_DEVICE_ID =
+            new byte[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2};
     private static final String TEST_APP_KEY_ALIAS = "rcleaver";
     private static final int TEST_GENERATION_ID = 2;
     private static final int TEST_CREDENTIAL_TYPE = CREDENTIAL_TYPE_PASSWORD;
@@ -104,6 +107,10 @@
         mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
         mKeyPair = SecureBox.genKeyPair();
 
+        mRecoverableKeyStoreDb.setRecoverySecretTypes(TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
+                new int[] {TYPE_LOCKSCREEN});
+        mRecoverableKeyStoreDb.setRecoverySecretTypes(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2,
+                new int[] {TYPE_LOCKSCREEN});
         mRecoverySnapshotStorage = new RecoverySnapshotStorage();
 
         mKeySyncTask = new KeySyncTask(
@@ -233,7 +240,7 @@
     @Test
     public void run_doesNotSendAnythingIfNoRecoveryAgentPendingIntentRegistered() throws Exception {
         SecretKey applicationKey = generateKey();
-        mRecoverableKeyStoreDb.setServerParameters(
+        mRecoverableKeyStoreDb.setServerParams(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_DEVICE_ID);
         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
         mRecoverableKeyStoreDb.insertKey(
@@ -269,7 +276,6 @@
 
     @Test
     public void run_sendsEncryptedKeysIfAvailableToSync() throws Exception {
-
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
@@ -277,14 +283,14 @@
                 addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
         mKeySyncTask.run();
 
-        KeyStoreRecoveryData recoveryData = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
-        KeyDerivationParameters keyDerivationParameters =
-                recoveryData.getRecoveryMetadata().get(0).getKeyDerivationParameters();
-        assertThat(keyDerivationParameters.getAlgorithm()).isEqualTo(
-                KeyDerivationParameters.ALGORITHM_SHA256);
+        RecoveryData recoveryData = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        KeyDerivationParams KeyDerivationParams =
+                recoveryData.getRecoveryMetadata().get(0).getKeyDerivationParams();
+        assertThat(KeyDerivationParams.getAlgorithm()).isEqualTo(
+                KeyDerivationParams.ALGORITHM_SHA256);
         verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
         byte[] lockScreenHash = KeySyncTask.hashCredentials(
-                keyDerivationParameters.getSalt(),
+                KeyDerivationParams.getSalt(),
                 TEST_CREDENTIAL);
         Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID);
         assertThat(counterId).isNotNull();
@@ -294,11 +300,11 @@
                 /*vaultParams=*/ KeySyncUtils.packVaultParams(
                         mKeyPair.getPublic(),
                         counterId,
-                        /*maxAttempts=*/ 10,
-                        TEST_DEVICE_ID));
-        List<KeyEntryRecoveryData> applicationKeys = recoveryData.getApplicationKeyBlobs();
+                        TEST_DEVICE_ID,
+                        /*maxAttempts=*/ 10));
+        List<EntryRecoveryData> applicationKeys = recoveryData.getEntryRecoveryData();
         assertThat(applicationKeys).hasSize(1);
-        KeyEntryRecoveryData keyData = applicationKeys.get(0);
+        EntryRecoveryData keyData = applicationKeys.get(0);
         assertEquals(TEST_APP_KEY_ALIAS, keyData.getAlias());
         assertThat(keyData.getAlias()).isEqualTo(keyData.getAlias());
         byte[] appKey = KeySyncUtils.decryptApplicationKey(
@@ -308,7 +314,6 @@
 
     @Test
     public void run_setsCorrectSnapshotVersion() throws Exception {
-
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
@@ -317,7 +322,7 @@
 
         mKeySyncTask.run();
 
-        KeyStoreRecoveryData recoveryData = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        RecoveryData recoveryData = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
         assertThat(recoveryData.getSnapshotVersion()).isEqualTo(1); // default value;
         mRecoverableKeyStoreDb.setShouldCreateSnapshot(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, true);
 
@@ -328,10 +333,88 @@
     }
 
     @Test
-    public void run_sendsEncryptedKeysWithTwoRegisteredAgents() throws Exception {
+    public void run_setsCorrectTypeForPassword() throws Exception {
+        mKeySyncTask = new KeySyncTask(
+                mRecoverableKeyStoreDb,
+                mRecoverySnapshotStorage,
+                mSnapshotListenersStorage,
+                TEST_USER_ID,
+                CREDENTIAL_TYPE_PASSWORD,
+                "password",
+                /*credentialUpdated=*/ false,
+                () -> mPlatformKeyManager);
 
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
+        SecretKey applicationKey =
+                addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+
+        mKeySyncTask.run();
+
+        RecoveryData recoveryData = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertThat(recoveryData.getRecoveryMetadata()).hasSize(1);
+        assertThat(recoveryData.getRecoveryMetadata().get(0).getLockScreenUiFormat()).
+                isEqualTo(TYPE_PASSWORD);
+    }
+
+   @Test
+    public void run_setsCorrectTypeForPin() throws Exception {
+        mKeySyncTask = new KeySyncTask(
+                mRecoverableKeyStoreDb,
+                mRecoverySnapshotStorage,
+                mSnapshotListenersStorage,
+                TEST_USER_ID,
+                CREDENTIAL_TYPE_PASSWORD,
+                /*credential=*/ "1234",
+                /*credentialUpdated=*/ false,
+                () -> mPlatformKeyManager);
+
+        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
+        SecretKey applicationKey =
+                addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+
+        mKeySyncTask.run();
+
+        RecoveryData recoveryData = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertThat(recoveryData.getRecoveryMetadata()).hasSize(1);
+        // Password with only digits is changed to pin.
+        assertThat(recoveryData.getRecoveryMetadata().get(0).getLockScreenUiFormat()).
+                isEqualTo(TYPE_PIN);
+    }
+
+    @Test
+    public void run_setsCorrectTypeForPattern() throws Exception {
+        mKeySyncTask = new KeySyncTask(
+                mRecoverableKeyStoreDb,
+                mRecoverySnapshotStorage,
+                mSnapshotListenersStorage,
+                TEST_USER_ID,
+                CREDENTIAL_TYPE_PATTERN,
+                "12345",
+                /*credentialUpdated=*/ false,
+                () -> mPlatformKeyManager);
+
+        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
+        SecretKey applicationKey =
+                addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+
+        mKeySyncTask.run();
+
+        RecoveryData recoveryData = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertThat(recoveryData.getRecoveryMetadata()).hasSize(1);
+        assertThat(recoveryData.getRecoveryMetadata().get(0).getLockScreenUiFormat()).
+                isEqualTo(TYPE_PATTERN);
+    }
+
+    @Test
+    public void run_sendsEncryptedKeysWithTwoRegisteredAgents() throws Exception {
+        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, mKeyPair.getPublic());
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
@@ -345,13 +428,35 @@
     }
 
     @Test
-    public void run_doesnSendKeyToNonregisteredAgent() throws Exception {
+    public void run_sendsEncryptedKeysOnlyForAgentWhichActiveUserSecretType() throws Exception {
+        mRecoverableKeyStoreDb.setRecoverySecretTypes(TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
+                new int[] {TYPE_LOCKSCREEN, 1000});
+        // Snapshot will not be created during unlock event.
+        mRecoverableKeyStoreDb.setRecoverySecretTypes(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2,
+                new int[] {1000});
 
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, mKeyPair.getPublic());
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
+        when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(true);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_APP_KEY_ALIAS);
+        mKeySyncTask.run();
+
+        verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
+        verify(mSnapshotListenersStorage, never()).
+                recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID2);
+    }
+
+    @Test
+    public void run_doesNotSendKeyToNonregisteredAgent() throws Exception {
+        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, mKeyPair.getPublic());
+        when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(false);
         addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
         addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_APP_KEY_ALIAS);
@@ -365,7 +470,7 @@
     private SecretKey addApplicationKey(int userId, int recoveryAgentUid, String alias)
             throws Exception{
         SecretKey applicationKey = generateKey();
-        mRecoverableKeyStoreDb.setServerParameters(
+        mRecoverableKeyStoreDb.setServerParams(
                 userId, recoveryAgentUid, TEST_DEVICE_ID);
         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, TEST_GENERATION_ID);
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
index 114da1a..3a9ff85 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
@@ -50,6 +50,8 @@
     private static final int RECOVERY_KEY_LENGTH_BITS = 256;
     private static final int THM_KF_HASH_SIZE = 256;
     private static final int KEY_CLAIMANT_LENGTH_BYTES = 16;
+    private static final byte[] TEST_DEVICE_ID =
+            new byte[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2};
     private static final String SHA_256_ALGORITHM = "SHA-256";
     private static final String APPLICATION_KEY_ALGORITHM = "AES";
     private static final byte[] LOCK_SCREEN_HASH_1 =
@@ -348,8 +350,8 @@
         byte[] packedForm = KeySyncUtils.packVaultParams(
                 thmPublicKey,
                 /*counterId=*/ 1001L,
-                /*maxAttempts=*/ 10,
-                /*deviceId=*/ 1L);
+                TEST_DEVICE_ID,
+                /*maxAttempts=*/ 10);
 
         assertEquals(VAULT_PARAMS_LENGTH_BYTES, packedForm.length);
     }
@@ -361,8 +363,8 @@
         byte[] packedForm = KeySyncUtils.packVaultParams(
                 thmPublicKey,
                 /*counterId=*/ 1001L,
-                /*maxAttempts=*/ 10,
-                /*deviceId=*/ 1L);
+                TEST_DEVICE_ID,
+                /*maxAttempts=*/ 10);
 
         assertArrayEquals(
                 SecureBox.encodePublicKey(thmPublicKey),
@@ -376,8 +378,8 @@
         byte[] packedForm = KeySyncUtils.packVaultParams(
                 SecureBox.genKeyPair().getPublic(),
                 counterId,
-                /*maxAttempts=*/ 10,
-                /*deviceId=*/ 1L);
+                TEST_DEVICE_ID,
+                /*maxAttempts=*/ 10);
 
         ByteBuffer byteBuffer = ByteBuffer.wrap(packedForm)
                 .order(ByteOrder.LITTLE_ENDIAN);
@@ -387,18 +389,17 @@
 
     @Test
     public void packVaultParams_encodesDeviceIdAsThirdParam() throws Exception {
-        long deviceId = 102942158152L;
 
         byte[] packedForm = KeySyncUtils.packVaultParams(
                 SecureBox.genKeyPair().getPublic(),
                 /*counterId=*/ 10021L,
-                /*maxAttempts=*/ 10,
-                deviceId);
+                TEST_DEVICE_ID,
+                /*maxAttempts=*/ 10);
 
         ByteBuffer byteBuffer = ByteBuffer.wrap(packedForm)
                 .order(ByteOrder.LITTLE_ENDIAN);
         byteBuffer.position(PUBLIC_KEY_LENGTH_BYTES + Long.BYTES);
-        assertEquals(deviceId, byteBuffer.getLong());
+        assertEquals(/* default value*/0, byteBuffer.getLong());
     }
 
     @Test
@@ -408,11 +409,12 @@
         byte[] packedForm = KeySyncUtils.packVaultParams(
                 SecureBox.genKeyPair().getPublic(),
                 /*counterId=*/ 1001L,
-                maxAttempts,
-                /*deviceId=*/ 1L);
+                TEST_DEVICE_ID,
+                maxAttempts);
 
         ByteBuffer byteBuffer = ByteBuffer.wrap(packedForm)
                 .order(ByteOrder.LITTLE_ENDIAN);
+        // TODO: update position.
         byteBuffer.position(PUBLIC_KEY_LENGTH_BYTES + 2 * Long.BYTES);
         assertEquals(maxAttempts, byteBuffer.getInt());
     }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index ac2d36b..1bdcf47 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -16,8 +16,8 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import static android.security.recoverablekeystore.KeyStoreRecoveryMetadata.TYPE_LOCKSCREEN;
-import static android.security.recoverablekeystore.KeyStoreRecoveryMetadata.TYPE_PASSWORD;
+import static android.security.keystore.RecoveryMetadata.TYPE_LOCKSCREEN;
+import static android.security.keystore.RecoveryMetadata.TYPE_PASSWORD;
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.junit.Assert.assertArrayEquals;
@@ -35,18 +35,19 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.Manifest;
 import android.os.Binder;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 import android.security.keystore.AndroidKeyStoreSecretKey;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
-import android.security.recoverablekeystore.KeyDerivationParameters;
-import android.security.recoverablekeystore.KeyEntryRecoveryData;
-import android.security.recoverablekeystore.KeyStoreRecoveryMetadata;
-import android.security.recoverablekeystore.RecoverableKeyStoreLoader;
-import android.support.test.InstrumentationRegistry;
+import android.security.keystore.KeyDerivationParams;
+import android.security.keystore.EntryRecoveryData;
+import android.security.keystore.RecoveryMetadata;
+import android.security.keystore.RecoveryManager;
 import android.support.test.filters.SmallTest;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
@@ -78,6 +79,7 @@
 public class RecoverableKeyStoreManagerTest {
     private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
 
+    private static final String ROOT_CERTIFICATE_ALIAS = "put_default_alias_here";
     private static final String TEST_SESSION_ID = "karlin";
     private static final byte[] TEST_PUBLIC_KEY = new byte[] {
         (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
@@ -206,10 +208,9 @@
     }
 
     @Test
-    public void removeKey_UpdatesShouldCreateSnapshot() throws Exception {
+    public void removeKey_updatesShouldCreateSnapshot() throws Exception {
         int uid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
-
         mRecoverableKeyStoreManager.generateAndStoreKey(TEST_ALIAS);
         // Pretend that key was synced
         mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
@@ -220,6 +221,29 @@
     }
 
     @Test
+    public void removeKey_failureDoesNotUpdateShouldCreateSnapshot() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+        // Key did not exist
+        mRecoverableKeyStoreManager.removeKey(TEST_ALIAS);
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
+    }
+
+    @Test
+    public void initRecoveryService_updatesShouldCreateSnapshot() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        // Sync is not needed.
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, TEST_PUBLIC_KEY);
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+    }
+
+    @Test
     public void startRecoverySession_checksPermissionFirst() throws Exception {
         mRecoverableKeyStoreManager.startRecoverySession(
                 TEST_SESSION_ID,
@@ -227,15 +251,15 @@
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
                 ImmutableList.of(
-                        new KeyStoreRecoveryMetadata(
+                        new RecoveryMetadata(
                                 TYPE_LOCKSCREEN,
                                 TYPE_PASSWORD,
-                                KeyDerivationParameters.createSha256Parameters(TEST_SALT),
+                                KeyDerivationParams.createSha256Params(TEST_SALT),
                                 TEST_SECRET)));
 
         verify(mMockContext, times(1))
                 .enforceCallingOrSelfPermission(
-                        eq(RecoverableKeyStoreLoader.PERMISSION_RECOVER_KEYSTORE), any());
+                        eq(Manifest.permission.RECOVER_KEYSTORE), any());
     }
 
     @Test
@@ -246,10 +270,10 @@
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
                 ImmutableList.of(
-                        new KeyStoreRecoveryMetadata(
+                        new RecoveryMetadata(
                                 TYPE_LOCKSCREEN,
                                 TYPE_PASSWORD,
-                                KeyDerivationParameters.createSha256Parameters(TEST_SALT),
+                                KeyDerivationParams.createSha256Params(TEST_SALT),
                                 TEST_SECRET)));
 
         assertEquals(1, mRecoverySessionStorage.size());
@@ -271,7 +295,7 @@
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
             assertThat(e.getMessage()).startsWith(
-                    "Only a single KeyStoreRecoveryMetadata is supported");
+                    "Only a single RecoveryMetadata is supported");
         }
     }
 
@@ -284,10 +308,10 @@
                     TEST_VAULT_PARAMS,
                     TEST_VAULT_CHALLENGE,
                     ImmutableList.of(
-                            new KeyStoreRecoveryMetadata(
+                            new RecoveryMetadata(
                                     TYPE_LOCKSCREEN,
                                     TYPE_PASSWORD,
-                                    KeyDerivationParameters.createSha256Parameters(TEST_SALT),
+                                    KeyDerivationParams.createSha256Params(TEST_SALT),
                                     TEST_SECRET)));
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
@@ -306,10 +330,10 @@
                     vaultParams,
                     TEST_VAULT_CHALLENGE,
                     ImmutableList.of(
-                            new KeyStoreRecoveryMetadata(
+                            new RecoveryMetadata(
                                     TYPE_LOCKSCREEN,
                                     TYPE_PASSWORD,
-                                    KeyDerivationParameters.createSha256Parameters(TEST_SALT),
+                                    KeyDerivationParams.createSha256Params(TEST_SALT),
                                     TEST_SECRET)));
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
@@ -324,7 +348,7 @@
                     TEST_SESSION_ID,
                     /*recoveryKeyBlob=*/ randomBytes(32),
                     /*applicationKeys=*/ ImmutableList.of(
-                            new KeyEntryRecoveryData("alias", randomBytes(32))
+                            new EntryRecoveryData("alias", randomBytes(32))
                     ));
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
@@ -339,10 +363,10 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeyStoreRecoveryMetadata(
+                ImmutableList.of(new RecoveryMetadata(
                         TYPE_LOCKSCREEN,
                         TYPE_PASSWORD,
-                        KeyDerivationParameters.createSha256Parameters(TEST_SALT),
+                        KeyDerivationParams.createSha256Params(TEST_SALT),
                         TEST_SECRET)));
 
         try {
@@ -363,17 +387,17 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeyStoreRecoveryMetadata(
+                ImmutableList.of(new RecoveryMetadata(
                         TYPE_LOCKSCREEN,
                         TYPE_PASSWORD,
-                        KeyDerivationParameters.createSha256Parameters(TEST_SALT),
+                        KeyDerivationParams.createSha256Params(TEST_SALT),
                         TEST_SECRET)));
         byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
                 .getKeyClaimant();
         SecretKey recoveryKey = randomRecoveryKey();
         byte[] encryptedClaimResponse = encryptClaimResponse(
                 keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
-        KeyEntryRecoveryData badApplicationKey = new KeyEntryRecoveryData(
+        EntryRecoveryData badApplicationKey = new EntryRecoveryData(
                 TEST_ALIAS,
                 randomBytes(32));
 
@@ -395,10 +419,10 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeyStoreRecoveryMetadata(
+                ImmutableList.of(new RecoveryMetadata(
                         TYPE_LOCKSCREEN,
                         TYPE_PASSWORD,
-                        KeyDerivationParameters.createSha256Parameters(TEST_SALT),
+                        KeyDerivationParams.createSha256Params(TEST_SALT),
                         TEST_SECRET)));
         byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
                 .getKeyClaimant();
@@ -406,7 +430,7 @@
         byte[] encryptedClaimResponse = encryptClaimResponse(
                 keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
         byte[] applicationKeyBytes = randomBytes(32);
-        KeyEntryRecoveryData applicationKey = new KeyEntryRecoveryData(
+        EntryRecoveryData applicationKey = new EntryRecoveryData(
                 TEST_ALIAS,
                 encryptedApplicationKey(recoveryKey, applicationKeyBytes));
 
@@ -449,6 +473,20 @@
     }
 
     @Test
+    public void setRecoverySecretTypes_updatesShouldCreateSnapshot() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        int[] types = new int[]{1, 2, 3};
+
+        mRecoverableKeyStoreManager.generateAndStoreKey(TEST_ALIAS);
+        // Pretend that key was synced
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+        mRecoverableKeyStoreManager.setRecoverySecretTypes(types);
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+    }
+
+    @Test
     public void setRecoveryStatus_forOneAlias() throws Exception {
         int userId = UserHandle.getCallingUserId();
         int uid = Binder.getCallingUid();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index b8080ab..5cb7b67 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -29,7 +29,7 @@
 
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.security.recoverablekeystore.RecoverableKeyStoreLoader;
+import android.security.keystore.RecoveryManager;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -51,6 +51,12 @@
     private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
     private File mDatabaseFile;
 
+    private static final byte[] SERVER_PARAMS =
+            new byte[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2};
+
+    private static final byte[] SERVER_PARAMS2 =
+            new byte[]{1, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4};
+
     @Before
     public void setUp() {
         Context context = InstrumentationRegistry.getTargetContext();
@@ -277,8 +283,7 @@
 
         Map<String, Integer> statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
         assertThat(statuses).hasSize(3);
-        assertThat(statuses).containsEntry(alias,
-                RecoverableKeyStoreLoader.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+        assertThat(statuses).containsEntry(alias, RecoveryManager.RECOVERY_STATUS_SYNC_IN_PROGRESS);
         assertThat(statuses).containsEntry(alias2, status);
         assertThat(statuses).containsEntry(alias3, status);
 
@@ -329,8 +334,7 @@
         int uid = 10009;
         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
 
-        long serverParams = 123456L;
-        mRecoverableKeyStoreDb.setServerParameters(userId, uid, serverParams);
+        mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
     }
 
@@ -438,32 +442,30 @@
 
         PublicKey pubkey1 = genRandomPublicKey();
         int[] types1 = new int[]{1};
-        long serverParams1 = 111L;
 
         PublicKey pubkey2 = genRandomPublicKey();
         int[] types2 = new int[]{2};
-        long serverParams2 = 222L;
 
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey1);
         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types1);
-        mRecoverableKeyStoreDb.setServerParameters(userId, uid, serverParams1);
+        mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
 
         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
                 types1);
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isEqualTo(
-                serverParams1);
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(
+                SERVER_PARAMS);
         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
                 pubkey1);
 
         // Check that the methods don't interfere with each other.
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey2);
         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types2);
-        mRecoverableKeyStoreDb.setServerParameters(userId, uid, serverParams2);
+        mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS2);
 
         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
                 types2);
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isEqualTo(
-                serverParams2);
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(
+                SERVER_PARAMS2);
         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
                 pubkey2);
     }
@@ -480,35 +482,33 @@
     }
 
     @Test
-    public void setServerParameters_replaceOldValue() throws Exception {
+    public void setServerParams_replaceOldValue() throws Exception {
         int userId = 12;
         int uid = 10009;
-        long serverParams1 = 111L;
-        long serverParams2 = 222L;
-        mRecoverableKeyStoreDb.setServerParameters(userId, uid, serverParams1);
-        mRecoverableKeyStoreDb.setServerParameters(userId, uid, serverParams2);
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isEqualTo(
-                serverParams2);
+
+        mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
+        mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS2);
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(
+                SERVER_PARAMS2);
     }
 
     @Test
-    public void getServerParameters_returnsNullIfNoValue() throws Exception {
+    public void getServerParams_returnsNullIfNoValue() throws Exception {
         int userId = 12;
         int uid = 10009;
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isNull();
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isNull();
 
         PublicKey pubkey = genRandomPublicKey();
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey);
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isNull();
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isNull();
     }
 
     @Test
-    public void getServerParameters_returnsInsertedValue() throws Exception {
+    public void getServerParams_returnsInsertedValue() throws Exception {
         int userId = 12;
         int uid = 10009;
-        long serverParams = 123456L;
-        mRecoverableKeyStoreDb.setServerParameters(userId, uid, serverParams);
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isEqualTo(serverParams);
+        mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(SERVER_PARAMS);
     }
 
     @Test
@@ -591,22 +591,21 @@
         int uid = 10009;
         PublicKey pubkey1 = genRandomPublicKey();
         PublicKey pubkey2 = genRandomPublicKey();
-        long serverParams = 123456L;
 
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey1);
         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
                 pubkey1);
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isNull();
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isNull();
 
-        mRecoverableKeyStoreDb.setServerParameters(userId, uid, serverParams);
+        mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
                 pubkey1);
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isEqualTo(serverParams);
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(SERVER_PARAMS);
 
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey2);
         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
                 pubkey2);
-        assertThat(mRecoverableKeyStoreDb.getServerParameters(userId, uid)).isEqualTo(serverParams);
+        assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(SERVER_PARAMS);
     }
 
     private static byte[] getUtf8Bytes(String s) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
index 2759e39..6308f74 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
@@ -3,7 +3,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
-import android.security.recoverablekeystore.KeyStoreRecoveryData;
+import android.security.keystore.RecoveryData;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -26,7 +26,7 @@
     @Test
     public void get_returnsSetSnapshot() {
         int userId = 1000;
-        KeyStoreRecoveryData recoveryData = new KeyStoreRecoveryData(
+        RecoveryData recoveryData = new RecoveryData(
                 /*snapshotVersion=*/ 1,
                 new ArrayList<>(),
                 new ArrayList<>(),
@@ -39,7 +39,7 @@
     @Test
     public void remove_removesSnapshots() {
         int userId = 1000;
-        KeyStoreRecoveryData recoveryData = new KeyStoreRecoveryData(
+        RecoveryData recoveryData = new RecoveryData(
                 /*snapshotVersion=*/ 1,
                 new ArrayList<>(),
                 new ArrayList<>(),
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index b073ee5..0abb48f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -294,6 +294,7 @@
                 null /*disabledPkg*/,
                 null /*sharedUser*/,
                 UPDATED_CODE_PATH /*codePath*/,
+                null /*resourcePath*/,
                 null /*legacyNativeLibraryPath*/,
                 "arm64-v8a" /*primaryCpuAbi*/,
                 "armeabi" /*secondaryCpuAbi*/,
@@ -327,6 +328,7 @@
                 null /*disabledPkg*/,
                 null /*sharedUser*/,
                 UPDATED_CODE_PATH /*codePath*/,
+                null /*resourcePath*/,
                 null /*legacyNativeLibraryPath*/,
                 "arm64-v8a" /*primaryCpuAbi*/,
                 "armeabi" /*secondaryCpuAbi*/,
@@ -367,6 +369,7 @@
                     null /*disabledPkg*/,
                     testUserSetting01 /*sharedUser*/,
                     UPDATED_CODE_PATH /*codePath*/,
+                    null /*resourcePath*/,
                     null /*legacyNativeLibraryPath*/,
                     "arm64-v8a" /*primaryCpuAbi*/,
                     "armeabi" /*secondaryCpuAbi*/,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 32b0b26..49601c3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -34,7 +34,6 @@
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
-import java.security.cert.Certificate;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -262,14 +261,13 @@
         assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData);
         assertEquals(a.mVersionName, b.mVersionName);
         assertEquals(a.mSharedUserId, b.mSharedUserId);
-        assertTrue(Arrays.equals(a.mSignatures, b.mSignatures));
-        assertTrue(Arrays.equals(a.mCertificates, b.mCertificates));
+        assertTrue(Arrays.equals(a.mSigningDetails.signatures, b.mSigningDetails.signatures));
         assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills));
         assertEquals(a.mExtras, b.mExtras);
         assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType);
         assertEquals(a.mRequiredAccountType, b.mRequiredAccountType);
         assertEquals(a.mOverlayTarget, b.mOverlayTarget);
-        assertEquals(a.mSigningKeys, b.mSigningKeys);
+        assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys);
         assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets);
         assertEquals(a.mKeySetMapping, b.mKeySetMapping);
         assertEquals(a.cpuAbiOverride, b.cpuAbiOverride);
@@ -495,14 +493,16 @@
         pkg.mAppMetaData = new Bundle();
         pkg.mVersionName = "foo17";
         pkg.mSharedUserId = "foo18";
-        pkg.mSignatures = new Signature[] { new Signature(new byte[16]) };
-        pkg.mCertificates = new Certificate[][] { new Certificate[] { null }};
+        pkg.mSigningDetails =
+                new PackageParser.SigningDetails(
+                        new Signature[] { new Signature(new byte[16]) },
+                        2,
+                        new ArraySet<>());
         pkg.mExtras = new Bundle();
         pkg.mRestrictedAccountType = "foo19";
         pkg.mRequiredAccountType = "foo20";
         pkg.mOverlayTarget = "foo21";
         pkg.mOverlayPriority = 100;
-        pkg.mSigningKeys = new ArraySet<>();
         pkg.mUpgradeKeySets = new ArraySet<>();
         pkg.mKeySetMapping = new ArrayMap<>();
         pkg.cpuAbiOverride = "foo22";
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index d1e0132..a628b7b 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.IApplicationToken;
@@ -43,6 +44,7 @@
     public boolean inMultiWindowMode;
     public boolean visible = true;
     public int surfaceLayer = 1;
+    public boolean isDimming = false;
 
     public boolean policyVisible = true;
 
@@ -221,7 +223,7 @@
 
     @Override
     public boolean isDimming() {
-        throw new UnsupportedOperationException("not implemented");
+        return isDimming;
     }
 
     @Override
@@ -253,4 +255,9 @@
     public boolean canAcquireSleepToken() {
         throw new UnsupportedOperationException("not implemented");
     }
+
+    @Override
+    public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId){
+        throw new UnsupportedOperationException("not implemented");
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
index 9a6da0e..b6c370e 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
@@ -16,15 +16,16 @@
 
 package com.android.server.policy;
 
-import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
@@ -34,7 +35,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.Surface;
 import android.view.WindowManager;
 
 import org.junit.Before;
@@ -128,7 +128,23 @@
     }
 
     @Test
-    public void layoutWindowLw_withDisplayCutout_fullscreen() {
+    public void layoutWindowLw_withhDisplayCutout_never() {
+        addDisplayCutout();
+
+        mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+        mPolicy.addWindow(mAppWindow);
+
+        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
+        assertInsetByTopBottom(mAppWindow.parentFrame, STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
         addDisplayCutout();
 
         mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
@@ -137,6 +153,22 @@
         mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
 
+        assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
+        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_withDisplayCutout_fullscreen() {
+        addDisplayCutout();
+
+        mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
+        mPolicy.addWindow(mAppWindow);
+
+        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
+
         assertInsetByTopBottom(mAppWindow.parentFrame, STATUS_BAR_HEIGHT, 0);
         assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
@@ -147,8 +179,8 @@
     public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
         addDisplayCutout();
 
-        mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-        mAppWindow.attrs.flags2 |= FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
+        mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
+        mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         mPolicy.addWindow(mAppWindow);
 
         mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -217,7 +249,7 @@
         setRotation(ROTATION_90);
 
         mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-        mAppWindow.attrs.flags2 |= FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
+        mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         mPolicy.addWindow(mAppWindow);
 
         mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
new file mode 100644
index 0000000..64637f4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.graphics.PixelFormat;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.WindowManager;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class PhoneWindowManagerTest {
+
+    private static FakeWindowState createOpaqueFullscreen(boolean hasLightNavBar) {
+        final FakeWindowState state = new FakeWindowState();
+        state.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT,
+                TYPE_BASE_APPLICATION,
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                PixelFormat.OPAQUE);
+        state.attrs.subtreeSystemUiVisibility =
+                hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0;
+        return state;
+    }
+
+    private static FakeWindowState createDimmingDialogWindow(boolean canBeImTarget) {
+        final FakeWindowState state = new FakeWindowState();
+        state.attrs = new WindowManager.LayoutParams(WRAP_CONTENT, WRAP_CONTENT,
+                TYPE_APPLICATION,
+                FLAG_DIM_BEHIND  | (canBeImTarget ? 0 : FLAG_ALT_FOCUSABLE_IM),
+                PixelFormat.TRANSLUCENT);
+        state.isDimming = true;
+        return state;
+    }
+
+    private static FakeWindowState createInputMethodWindow(boolean visible, boolean drawNavBar,
+            boolean hasLightNavBar) {
+        final FakeWindowState state = new FakeWindowState();
+        state.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT,
+                TYPE_INPUT_METHOD,
+                FLAG_NOT_FOCUSABLE | FLAG_LAYOUT_IN_SCREEN
+                        | (drawNavBar ? FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS : 0),
+                PixelFormat.TRANSPARENT);
+        state.attrs.subtreeSystemUiVisibility =
+                hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0;
+        state.visible = visible;
+        state.policyVisible = visible;
+        return state;
+    }
+
+
+    @Test
+    public void testChooseNavigationColorWindowLw() throws Exception {
+        final FakeWindowState opaque = createOpaqueFullscreen(false);
+
+        final FakeWindowState dimmingImTarget = createDimmingDialogWindow(true);
+        final FakeWindowState dimmingNonImTarget = createDimmingDialogWindow(false);
+
+        final FakeWindowState visibleIme = createInputMethodWindow(true, true, false);
+        final FakeWindowState invisibleIme = createInputMethodWindow(false, true, false);
+        final FakeWindowState imeNonDrawNavBar = createInputMethodWindow(true, false, false);
+
+        // If everything is null, return null
+        assertNull(null, PhoneWindowManager.chooseNavigationColorWindowLw(
+                null, null, null, NAV_BAR_BOTTOM));
+
+        assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, opaque, null, NAV_BAR_BOTTOM));
+        assertEquals(dimmingImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, dimmingImTarget, null, NAV_BAR_BOTTOM));
+        assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, dimmingNonImTarget, null, NAV_BAR_BOTTOM));
+
+        assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw(
+                null, null, visibleIme, NAV_BAR_BOTTOM));
+        assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw(
+                null, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM));
+        assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
+                null, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM));
+        assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, opaque, visibleIme, NAV_BAR_BOTTOM));
+        assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM));
+        assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM));
+
+        assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, opaque, invisibleIme, NAV_BAR_BOTTOM));
+        assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, opaque, invisibleIme, NAV_BAR_BOTTOM));
+        assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, opaque, visibleIme, NAV_BAR_RIGHT));
+
+        // Only IME windows that have FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS should be navigation color
+        // window.
+        assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, opaque, imeNonDrawNavBar, NAV_BAR_BOTTOM));
+        assertEquals(dimmingImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, dimmingImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM));
+        assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
+                opaque, dimmingNonImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM));
+    }
+
+    @Test
+    public void testUpdateLightNavigationBarLw() throws Exception {
+        final FakeWindowState opaqueDarkNavBar = createOpaqueFullscreen(false);
+        final FakeWindowState opaqueLightNavBar = createOpaqueFullscreen(true);
+
+        final FakeWindowState dimming = createDimmingDialogWindow(false);
+
+        final FakeWindowState imeDrawDarkNavBar = createInputMethodWindow(true,true, false);
+        final FakeWindowState imeDrawLightNavBar = createInputMethodWindow(true,true, true);
+
+        assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                PhoneWindowManager.updateLightNavigationBarLw(
+                        SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null,
+                        null, null));
+
+        // Opaque top fullscreen window overrides SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR flag.
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                0, opaqueDarkNavBar, opaqueDarkNavBar, null, opaqueDarkNavBar));
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, opaqueDarkNavBar, null,
+                opaqueDarkNavBar));
+        assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                PhoneWindowManager.updateLightNavigationBarLw(0, opaqueLightNavBar,
+                        opaqueLightNavBar, null, opaqueLightNavBar));
+        assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                PhoneWindowManager.updateLightNavigationBarLw(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                        opaqueLightNavBar, opaqueLightNavBar, null, opaqueLightNavBar));
+
+        // Dimming window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                0, opaqueDarkNavBar, dimming, null, dimming));
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                0, opaqueLightNavBar, dimming, null, dimming));
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, dimming, null, dimming));
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, null, dimming));
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, imeDrawLightNavBar,
+                dimming));
+
+        // IME window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null, imeDrawDarkNavBar,
+                imeDrawDarkNavBar));
+
+        // Even if the top fullscreen has SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, IME window wins.
+        assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
+                SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, opaqueLightNavBar,
+                imeDrawDarkNavBar, imeDrawDarkNavBar));
+
+        // IME window should be able to use SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
+        assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                PhoneWindowManager.updateLightNavigationBarLw(0, opaqueDarkNavBar,
+                        opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
index e7e9abad..ad89953 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -24,6 +24,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
+import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 
@@ -31,6 +33,8 @@
 import android.content.ContextWrapper;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.Path;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.IBinder;
@@ -38,6 +42,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.testing.TestableResources;
 import android.view.Display;
+import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.View;
@@ -65,6 +70,9 @@
 
     FakeWindowState mStatusBar;
     FakeWindowState mNavigationBar;
+    private boolean mHasDisplayCutout;
+    private int mRotation = ROTATION_0;
+    private final Matrix mTmpMatrix = new Matrix();
 
     @Before
     public void setUpBase() throws Exception {
@@ -80,16 +88,32 @@
 
         mPolicy = TestablePhoneWindowManager.create(mContext);
 
-        setRotation(ROTATION_0);
+        updateDisplayFrames();
     }
 
     public void setRotation(int rotation) {
+        mRotation = rotation;
+        updateDisplayFrames();
+    }
+
+    private void updateDisplayFrames() {
         DisplayInfo info = new DisplayInfo();
 
-        final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
+        final boolean flippedDimensions = mRotation == ROTATION_90 || mRotation == ROTATION_270;
         info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
         info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
-        info.rotation = rotation;
+        info.rotation = mRotation;
+        if (mHasDisplayCutout) {
+            Path p = new Path();
+            p.addRect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT,
+                    Path.Direction.CCW);
+            transformPhysicalToLogicalCoordinates(
+                    mRotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, mTmpMatrix);
+            p.transform(mTmpMatrix);
+            info.displayCutout = DisplayCutout.fromBounds(p);
+        } else {
+            info.displayCutout = null;
+        }
 
         mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info);
     }
@@ -116,7 +140,8 @@
     }
 
     public void addDisplayCutout() {
-        mPolicy.mEmulateDisplayCutout = true;
+        mHasDisplayCutout = true;
+        updateDisplayFrames();
     }
 
     /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 725fb21..40964c0 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -34,13 +34,13 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
 import android.app.usage.UsageEvents;
-import android.app.usage.UsageStatsManager;
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -55,6 +55,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
 import android.view.Display;
 
 import com.android.server.SystemService;
@@ -65,7 +66,9 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Unit test for AppStandbyController.
@@ -78,6 +81,11 @@
     private static final String PACKAGE_1 = "com.example.foo";
     private static final int UID_1 = 10000;
     private static final int USER_ID = 0;
+    private static final int USER_ID2 = 10;
+
+    private static final String ADMIN_PKG = "com.android.admin";
+    private static final String ADMIN_PKG2 = "com.android.admin2";
+    private static final String ADMIN_PKG3 = "com.android.admin3";
 
     private static final long MINUTE_MS = 60 * 1000;
     private static final long HOUR_MS = 60 * MINUTE_MS;
@@ -454,6 +462,105 @@
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
                 REASON_PREDICTED, mInjector.mElapsedRealtime);
         assertBucket(STANDBY_BUCKET_FREQUENT);
+    }
 
+    @Test
+    public void testAddActiveDeviceAdmin() {
+        assertActiveAdmins(USER_ID, (String[]) null);
+        assertActiveAdmins(USER_ID2, (String[]) null);
+
+        mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
+        assertActiveAdmins(USER_ID, ADMIN_PKG);
+        assertActiveAdmins(USER_ID2, (String[]) null);
+
+        mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
+        assertActiveAdmins(USER_ID, ADMIN_PKG);
+        assertActiveAdmins(USER_ID2, (String[]) null);
+
+        mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
+        assertActiveAdmins(USER_ID, ADMIN_PKG);
+        assertActiveAdmins(USER_ID2, ADMIN_PKG2);
+    }
+
+    @Test
+    public void testSetActiveAdminApps() {
+        assertActiveAdmins(USER_ID, (String[]) null);
+        assertActiveAdmins(USER_ID2, (String[]) null);
+
+        setActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
+        assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
+        assertActiveAdmins(USER_ID2, (String[]) null);
+
+        mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
+        setActiveAdmins(USER_ID2, ADMIN_PKG);
+        assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
+        assertActiveAdmins(USER_ID2, ADMIN_PKG);
+
+        mController.setActiveAdminApps(null, USER_ID);
+        assertActiveAdmins(USER_ID, (String[]) null);
+    }
+
+    @Test
+    public void isActiveDeviceAdmin() {
+        assertActiveAdmins(USER_ID, (String[]) null);
+        assertActiveAdmins(USER_ID2, (String[]) null);
+
+        mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
+        assertIsActiveAdmin(ADMIN_PKG, USER_ID);
+        assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
+
+        mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
+        mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID2);
+        assertIsActiveAdmin(ADMIN_PKG, USER_ID);
+        assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
+        assertIsActiveAdmin(ADMIN_PKG, USER_ID2);
+        assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
+
+        setActiveAdmins(USER_ID2, ADMIN_PKG2);
+        assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
+        assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
+        assertIsActiveAdmin(ADMIN_PKG, USER_ID);
+        assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
+    }
+
+    private String getAdminAppsStr(int userId) {
+        return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
+    }
+
+    private String getAdminAppsStr(int userId, Set<String> adminApps) {
+        return "admin apps for u" + userId + ": "
+                + (adminApps == null ? "null" : Arrays.toString(adminApps.toArray()));
+    }
+
+    private void assertIsActiveAdmin(String adminApp, int userId) {
+        assertTrue(adminApp + " should be an active admin; " + getAdminAppsStr(userId),
+                mController.isActiveDeviceAdmin(adminApp, userId));
+    }
+
+    private void assertIsNotActiveAdmin(String adminApp, int userId) {
+        assertFalse(adminApp + " shouldn't be an active admin; " + getAdminAppsStr(userId),
+                mController.isActiveDeviceAdmin(adminApp, userId));
+    }
+
+    private void assertActiveAdmins(int userId, String... admins) {
+        final Set<String> actualAdminApps = mController.getActiveAdminAppsForTest(userId);
+        if (admins == null) {
+            if (actualAdminApps != null && !actualAdminApps.isEmpty()) {
+                fail("Admin apps should be null; " + getAdminAppsStr(userId, actualAdminApps));
+            }
+            return;
+        }
+        assertEquals("No. of admin apps not equal; " + getAdminAppsStr(userId, actualAdminApps)
+                + "; expected=" + Arrays.toString(admins), admins.length, actualAdminApps.size());
+        final Set<String> adminAppsCopy = new ArraySet<>(actualAdminApps);
+        for (String admin : admins) {
+            adminAppsCopy.remove(admin);
+        }
+        assertTrue("Unexpected admin apps; " + getAdminAppsStr(userId, actualAdminApps)
+                + "; expected=" + Arrays.toString(admins), adminAppsCopy.isEmpty());
+    }
+
+    private void setActiveAdmins(int userId, String... admins) {
+        mController.setActiveAdminApps(new ArraySet<>(Arrays.asList(admins)), userId);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 693264c..2284bbb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -37,13 +37,18 @@
 
 import android.annotation.SuppressLint;
 import android.content.res.Configuration;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.DisplayMetrics;
 import android.util.SparseIntArray;
+import android.view.DisplayCutout;
 import android.view.MotionEvent;
+import android.view.Surface;
 
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -53,7 +58,7 @@
  * Tests for the {@link DisplayContent} class.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.DisplayContentTests
+ *  atest com.android.server.wm.DisplayContentTests
  */
 @SmallTest
 @Presubmit
@@ -385,6 +390,38 @@
     }
 
     @Test
+    public void testDisplayCutout_rot0() throws Exception {
+        synchronized (sWm.getWindowManagerLock()) {
+            final DisplayContent dc = createNewDisplay();
+            dc.mInitialDisplayWidth = 200;
+            dc.mInitialDisplayHeight = 400;
+            final DisplayCutout cutout = createCutout(new Rect(80, 0, 120, 10));
+
+            dc.mInitialDisplayCutout = cutout;
+            dc.setRotation(Surface.ROTATION_0);
+            dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
+
+            assertEquals(cutout, dc.getDisplayInfo().displayCutout);
+        }
+    }
+
+    @Test
+    public void testDisplayCutout_rot90() throws Exception {
+        synchronized (sWm.getWindowManagerLock()) {
+            final DisplayContent dc = createNewDisplay();
+            dc.mInitialDisplayWidth = 200;
+            dc.mInitialDisplayHeight = 400;
+            final DisplayCutout cutout = createCutout(new Rect(80, 0, 120, 10));
+
+            dc.mInitialDisplayCutout = cutout;
+            dc.setRotation(Surface.ROTATION_90);
+            dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
+
+            assertEquals(createCutout(new Rect(0, 80, 10, 120)), dc.getDisplayInfo().displayCutout);
+        }
+    }
+
+    @Test
     @SuppressLint("InlinedApi")
     public void testOrientationDefinedByKeyguard() {
         final DisplayContent dc = createNewDisplay();
@@ -449,4 +486,10 @@
                 y,
                 metaState);
     }
+
+    private DisplayCutout createCutout(Rect r) {
+        Path p = new Path();
+        p.addRect(r.left, r.top, r.right, r.bottom, Path.Direction.CCW);
+        return DisplayCutout.fromBounds(p);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index ce76a22..ac29163 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -16,27 +16,38 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.content.ClipData;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.InputChannel;
 import android.view.Surface;
 import android.view.SurfaceSession;
+import android.view.View;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+
 /**
  * Tests for the {@link DragDropController} class.
  *
@@ -46,36 +57,92 @@
 @RunWith(AndroidJUnit4.class)
 @Presubmit
 public class DragDropControllerTests extends WindowTestsBase {
-    private static final int TIMEOUT_MS = 1000;
-    private DragDropController mTarget;
+    private static final int TIMEOUT_MS = 3000;
+    private TestDragDropController mTarget;
     private WindowState mWindow;
     private IBinder mToken;
 
+    static class TestDragDropController extends DragDropController {
+        @GuardedBy("sWm.mWindowMap")
+        private Runnable mCloseCallback;
+
+        TestDragDropController(WindowManagerService service, Looper looper) {
+            super(service, looper);
+        }
+
+        void setOnClosedCallbackLocked(Runnable runnable) {
+            assertTrue(dragDropActiveLocked());
+            mCloseCallback = runnable;
+        }
+
+        @Override
+        void onDragStateClosedLocked(DragState dragState) {
+            super.onDragStateClosedLocked(dragState);
+            if (mCloseCallback != null) {
+                mCloseCallback.run();
+                mCloseCallback = null;
+            }
+        }
+    }
+
+    /**
+     * Creates a window state which can be used as a drop target.
+     */
+    private WindowState createDropTargetWindow(String name, int ownerId) {
+        final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(
+                mDisplayContent);
+        final TaskStack stack = createStackControllerOnStackOnDisplay(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+        final Task task = createTaskInStack(stack, ownerId);
+        task.addChild(token, 0);
+
+        final WindowState window = createWindow(
+                null, TYPE_BASE_APPLICATION, token, name, ownerId, false);
+        window.mInputChannel = new InputChannel();
+        window.mHasSurface = true;
+        return window;
+    }
+
     @Before
     public void setUp() throws Exception {
+        final UserManagerInternal userManager = mock(UserManagerInternal.class);
+        LocalServices.addService(UserManagerInternal.class, userManager);
+
         super.setUp();
-        assertNotNull(sWm.mDragDropController);
-        mTarget = sWm.mDragDropController;
-        mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
+
+        mTarget = new TestDragDropController(sWm, sWm.mH.getLooper());
+        mDisplayContent = spy(mDisplayContent);
+        mWindow = createDropTargetWindow("Drag test window", 0);
+        when(mDisplayContent.getTouchableWinAtPointLocked(0, 0)).thenReturn(mWindow);
+        when(sWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
+
         synchronized (sWm.mWindowMap) {
-            // Because sWm is a static object, the previous operation may remain.
-            assertFalse(mTarget.dragDropActiveLocked());
+            sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         }
     }
 
     @After
-    public void tearDown() {
-        if (mToken != null) {
-            mTarget.cancelDragAndDrop(mToken);
+    public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        final CountDownLatch latch;
+        synchronized (sWm.mWindowMap) {
+            if (!mTarget.dragDropActiveLocked()) {
+                return;
+            }
+            if (mToken != null) {
+                mTarget.cancelDragAndDrop(mToken);
+            }
+            latch = new CountDownLatch(1);
+            mTarget.setOnClosedCallbackLocked(() -> {
+                latch.countDown();
+            });
         }
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     @Test
-    public void testPrepareDrag() throws Exception {
-        final Surface surface = new Surface();
-        mToken = mTarget.prepareDrag(
-                new SurfaceSession(), 0, 0, mWindow.mClient, 0, 100, 100, surface);
-        assertNotNull(mToken);
+    public void testDragFlow() throws Exception {
+        dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
     }
 
     @Test
@@ -85,4 +152,33 @@
                 new SurfaceSession(), 0, 0, mWindow.mClient, 0, 0, 0, surface);
         assertNull(mToken);
     }
+
+    @Test
+    public void testPerformDrag_NullDataWithGrantUri() throws Exception {
+        dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
+    }
+
+    @Test
+    public void testPerformDrag_NullDataToOtherUser() throws Exception {
+        final WindowState otherUsersWindow =
+                createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
+        when(mDisplayContent.getTouchableWinAtPointLocked(10, 10))
+                .thenReturn(otherUsersWindow);
+
+        dragFlow(0, null, 10, 10);
+    }
+
+    private void dragFlow(int flag, ClipData data, float dropX, float dropY) {
+        final Surface surface = new Surface();
+        mToken = mTarget.prepareDrag(
+                new SurfaceSession(), 0, 0, mWindow.mClient, flag, 100, 100, surface);
+        assertNotNull(mToken);
+
+        assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
+        assertTrue(mTarget.performDrag(
+                mWindow.mClient, mToken, 0, 0, 0, 0, 0, data));
+
+        mTarget.handleMotionEvent(false, dropX, dropY);
+        mToken = mWindow.mClient.asBinder();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index c735341..5ed17cc 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -416,7 +416,8 @@
     }
 
     @Override
-    public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback) {
+    public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback,
+            CharSequence message) {
     }
 
     @Override
@@ -588,6 +589,7 @@
         return false;
     }
 
+    @NavigationBarPosition
     @Override
     public int getNavBarPosition() {
         return NAV_BAR_BOTTOM;
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index c699a94..69b1378 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -230,20 +230,22 @@
             boolean ownerCanAddInternalSystemWindow) {
         final WindowToken token = createWindowToken(
                 dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
-        return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow);
+        return createWindow(parent, type, token, name, 0 /* ownerId */,
+                ownerCanAddInternalSystemWindow);
     }
 
     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
-        return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */);
+        return createWindow(parent, type, token, name, 0 /* ownerId */,
+                false /* ownerCanAddInternalSystemWindow */);
     }
 
     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
-            boolean ownerCanAddInternalSystemWindow) {
+            int ownerId, boolean ownerCanAddInternalSystemWindow) {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
         attrs.setTitle(name);
 
         final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
-                0, attrs, VISIBLE, 0, ownerCanAddInternalSystemWindow);
+                0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
         // adding it to the token...
         token.addWindow(w);
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
new file mode 100644
index 0000000..40a10e0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.utils;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.PointF;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+
+public class CoordinateTransformsTest {
+
+    private static final int W = 200;
+    private static final int H = 400;
+
+    private final Matrix mMatrix = new Matrix();
+
+    @Rule
+    public final ErrorCollector mErrorCollector = new ErrorCollector();
+
+    @Before
+    public void setUp() throws Exception {
+        mMatrix.setTranslate(0xdeadbeef, 0xdeadbeef);
+    }
+
+    @Test
+    public void transformPhysicalToLogicalCoordinates_rot0() throws Exception {
+        transformPhysicalToLogicalCoordinates(ROTATION_0, W, H, mMatrix);
+        assertThat(mMatrix, is(Matrix.IDENTITY_MATRIX));
+    }
+
+    @Test
+    public void transformPhysicalToLogicalCoordinates_rot90() throws Exception {
+        transformPhysicalToLogicalCoordinates(ROTATION_90, W, H, mMatrix);
+
+        checkDevicePoint(0, 0).mapsToLogicalPoint(0, W);
+        checkDevicePoint(W, H).mapsToLogicalPoint(H, 0);
+    }
+
+    @Test
+    public void transformPhysicalToLogicalCoordinates_rot180() throws Exception {
+        transformPhysicalToLogicalCoordinates(ROTATION_180, W, H, mMatrix);
+
+        checkDevicePoint(0, 0).mapsToLogicalPoint(W, H);
+        checkDevicePoint(W, H).mapsToLogicalPoint(0, 0);
+    }
+
+    @Test
+    public void transformPhysicalToLogicalCoordinates_rot270() throws Exception {
+        transformPhysicalToLogicalCoordinates(ROTATION_270, W, H, mMatrix);
+
+        checkDevicePoint(0, 0).mapsToLogicalPoint(H, 0);
+        checkDevicePoint(W, H).mapsToLogicalPoint(0, W);
+    }
+
+    private DevicePointAssertable checkDevicePoint(int x, int y) {
+        final Point devicePoint = new Point(x, y);
+        final float[] fs = new float[] {x, y};
+        mMatrix.mapPoints(fs);
+        final PointF transformedPoint = new PointF(fs[0], fs[1]);
+
+        return (expectedX, expectedY) -> {
+            mErrorCollector.checkThat("t(" + devicePoint + ")",
+                    transformedPoint, is(new PointF(expectedX, expectedY)));
+        };
+    }
+
+    public interface DevicePointAssertable {
+        void mapsToLogicalPoint(int x, int y);
+    }
+}
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
index 58f0ded..a60d715 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
@@ -47,7 +47,7 @@
     public void testSingleString() throws Exception {
         String[] expected = { "foobar" };
         Bundle bundle = new Bundle();
-        bundle.putString(Notification.EXTRA_PEOPLE, expected[0]);
+        bundle.putString(Notification.EXTRA_PEOPLE_LIST, expected[0]);
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("string should be in result[0]", expected, result);
     }
@@ -56,7 +56,7 @@
     public void testSingleCharArray() throws Exception {
         String[] expected = { "foobar" };
         Bundle bundle = new Bundle();
-        bundle.putCharArray(Notification.EXTRA_PEOPLE, expected[0].toCharArray());
+        bundle.putCharArray(Notification.EXTRA_PEOPLE_LIST, expected[0].toCharArray());
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("char[] should be in result[0]", expected, result);
     }
@@ -65,7 +65,7 @@
     public void testSingleCharSequence() throws Exception {
         String[] expected = { "foobar" };
         Bundle bundle = new Bundle();
-        bundle.putCharSequence(Notification.EXTRA_PEOPLE, new SpannableString(expected[0]));
+        bundle.putCharSequence(Notification.EXTRA_PEOPLE_LIST, new SpannableString(expected[0]));
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("charSequence should be in result[0]", expected, result);
     }
@@ -74,7 +74,7 @@
     public void testStringArraySingle() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foobar" };
-        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
+        bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected);
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("wrapped string should be in result[0]", expected, result);
     }
@@ -83,7 +83,7 @@
     public void testStringArrayMultiple() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foo", "bar", "baz" };
-        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
+        bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected);
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("testStringArrayMultiple", expected, result);
     }
@@ -92,7 +92,7 @@
     public void testStringArrayNulls() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foo", null, "baz" };
-        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
+        bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected);
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("testStringArrayNulls", expected, result);
     }
@@ -105,7 +105,7 @@
         for (int i = 0; i < expected.length; i++) {
             charSeqArray[i] = new SpannableString(expected[i]);
         }
-        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE, charSeqArray);
+        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE_LIST, charSeqArray);
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("testCharSequenceArrayMultiple", expected, result);
     }
@@ -122,7 +122,7 @@
                 charSeqArray[i] = new SpannableString(expected[i]);
             }
         }
-        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE, charSeqArray);
+        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE_LIST, charSeqArray);
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("testMixedCharSequenceArrayList", expected, result);
     }
@@ -135,7 +135,7 @@
         for (int i = 0; i < expected.length; i++) {
             stringArrayList.add(expected[i]);
         }
-        bundle.putStringArrayList(Notification.EXTRA_PEOPLE, stringArrayList);
+        bundle.putStringArrayList(Notification.EXTRA_PEOPLE_LIST, stringArrayList);
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("testStringArrayList", expected, result);
     }
@@ -149,11 +149,24 @@
         for (int i = 0; i < expected.length; i++) {
             stringArrayList.add(new SpannableString(expected[i]));
         }
-        bundle.putCharSequenceArrayList(Notification.EXTRA_PEOPLE, stringArrayList);
+        bundle.putCharSequenceArrayList(Notification.EXTRA_PEOPLE_LIST, stringArrayList);
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertStringArrayEquals("testCharSequenceArrayList", expected, result);
     }
 
+    @Test
+    public void testPeopleArrayList() throws Exception {
+        Bundle bundle = new Bundle();
+        String[] expected = { "name:test" , "tel:1234" };
+        final ArrayList<Notification.Person> arrayList =
+                new ArrayList<>(expected.length);
+        arrayList.add(new Notification.Person().setName("test"));
+        arrayList.add(new Notification.Person().setUri(expected[1]));
+        bundle.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, arrayList);
+        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
+        assertStringArrayEquals("testPeopleArrayList", expected, result);
+    }
+
     private void assertStringArrayEquals(String message, String[] expected, String[] result) {
         String expectedString = Arrays.toString(expected);
         String resultString = Arrays.toString(result);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 0c7397a..c532a8a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -107,6 +107,68 @@
     }
 
     @Test
+    public void testAlarmsOnly_alarmMediaMuteNotApplied() {
+        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS;
+        mZenModeHelperSpy.mConfig.allowAlarms = false;
+        mZenModeHelperSpy.mConfig.allowMediaSystemOther = false;
+        assertFalse(mZenModeHelperSpy.mConfig.allowAlarms);
+        assertFalse(mZenModeHelperSpy.mConfig.allowMediaSystemOther);
+        mZenModeHelperSpy.applyRestrictions();
+
+        // Alarms only mode will not silence alarms
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_ALARM);
+
+        // Alarms only mode will not silence media
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_MEDIA);
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_GAME);
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_ASSISTANCE_SONIFICATION);
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_UNKNOWN);
+    }
+
+    @Test
+    public void testAlarmsOnly_callsMuteApplied() {
+        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS;
+        mZenModeHelperSpy.mConfig.allowCalls = true;
+        assertTrue(mZenModeHelperSpy.mConfig.allowCalls);
+        mZenModeHelperSpy.applyRestrictions();
+
+        // Alarms only mode will silence calls despite priority-mode config
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+                AudioAttributes.USAGE_NOTIFICATION_RINGTONE);
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+                AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST);
+    }
+
+    @Test
+    public void testAlarmsOnly_allZenConfigToggledCannotBypass_alarmMuteNotApplied() {
+        // Only audio attributes with SUPPRESIBLE_NEVER can bypass
+        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS;
+        mZenModeHelperSpy.mConfig.allowAlarms = false;
+        mZenModeHelperSpy.mConfig.allowMediaSystemOther = false;
+        mZenModeHelperSpy.mConfig.allowReminders = false;
+        mZenModeHelperSpy.mConfig.allowCalls = false;
+        mZenModeHelperSpy.mConfig.allowMessages = false;
+        mZenModeHelperSpy.mConfig.allowEvents = false;
+        mZenModeHelperSpy.mConfig.allowRepeatCallers= false;
+        assertFalse(mZenModeHelperSpy.mConfig.allowAlarms);
+        assertFalse(mZenModeHelperSpy.mConfig.allowMediaSystemOther);
+        assertFalse(mZenModeHelperSpy.mConfig.allowReminders);
+        assertFalse(mZenModeHelperSpy.mConfig.allowCalls);
+        assertFalse(mZenModeHelperSpy.mConfig.allowMessages);
+        assertFalse(mZenModeHelperSpy.mConfig.allowEvents);
+        assertFalse(mZenModeHelperSpy.mConfig.allowRepeatCallers);
+        mZenModeHelperSpy.applyRestrictions();
+
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_ALARM);
+    }
+
+    @Test
     public void testZenAllCannotBypass() {
         // Only audio attributes with SUPPRESIBLE_NEVER can bypass
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 2ec218a..ff3d586 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -33,7 +33,6 @@
 
 import android.app.ActivityManager;
 import android.app.AppGlobals;
-import android.app.admin.DevicePolicyManager;
 import android.app.usage.UsageStatsManager.StandbyBuckets;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
@@ -66,13 +65,16 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
+import android.util.ArraySet;
 import android.util.KeyValueListParser;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.view.Display;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
@@ -87,6 +89,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Manages the standby state of an app, listening to various events.
@@ -147,6 +150,9 @@
     @GuardedBy("mAppIdleLock")
     private List<String> mCarrierPrivilegedApps;
 
+    @GuardedBy("mActiveAdminApps")
+    private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
+
     // Messages for the handler
     static final int MSG_INFORM_LISTENERS = 3;
     static final int MSG_FORCE_IDLE_STATE = 4;
@@ -619,6 +625,9 @@
     public void onUserRemoved(int userId) {
         synchronized (mAppIdleLock) {
             mAppIdleHistory.onUserRemoved(userId);
+            synchronized (mActiveAdminApps) {
+                mActiveAdminApps.remove(userId);
+            }
         }
     }
 
@@ -857,10 +866,39 @@
                 newBucket);
     }
 
-    private boolean isActiveDeviceAdmin(String packageName, int userId) {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        if (dpm == null) return false;
-        return dpm.packageHasActiveAdmins(packageName, userId);
+    @VisibleForTesting
+    boolean isActiveDeviceAdmin(String packageName, int userId) {
+        synchronized (mActiveAdminApps) {
+            final Set<String> adminPkgs = mActiveAdminApps.get(userId);
+            return adminPkgs != null && adminPkgs.contains(packageName);
+        }
+    }
+
+    public void addActiveDeviceAdmin(String adminPkg, int userId) {
+        synchronized (mActiveAdminApps) {
+            Set<String> adminPkgs = mActiveAdminApps.get(userId);
+            if (adminPkgs == null) {
+                adminPkgs = new ArraySet<>();
+                mActiveAdminApps.put(userId, adminPkgs);
+            }
+            adminPkgs.add(adminPkg);
+        }
+    }
+
+    public void setActiveAdminApps(Set<String> adminPkgs, int userId) {
+        synchronized (mActiveAdminApps) {
+            if (adminPkgs == null) {
+                mActiveAdminApps.remove(userId);
+            } else {
+                mActiveAdminApps.put(userId, adminPkgs);
+            }
+        }
+    }
+
+    Set<String> getActiveAdminAppsForTest(int userId) {
+        synchronized (mActiveAdminApps) {
+            return mActiveAdminApps.get(userId);
+        }
     }
 
     /**
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 463a26e..78cc81f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -70,6 +70,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * A service that collects, aggregates, and persists application usage data.
@@ -1020,5 +1021,14 @@
         public long getTimeSinceLastJobRun(String packageName, int userId) {
             return mAppStandby.getTimeSinceLastJobRun(packageName, userId);
         }
+
+        public void onActiveAdminAdded(String packageName, int userId) {
+            mAppStandby.addActiveDeviceAdmin(packageName, userId);
+        }
+
+        @Override
+        public void setActiveAdminApps(Set<String> packageNames, int userId) {
+            mAppStandby.setActiveAdminApps(packageNames, userId);
+        }
     }
 }
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2091101..8c7d6b3 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1408,7 +1408,7 @@
      * @param extras Bundle containing extra information associated with the event.
      */
     public void sendCallEvent(String event, Bundle extras) {
-        mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras);
+        mInCallAdapter.sendCallEvent(mTelecomCallId, event, mTargetSdkVersion, extras);
     }
 
     /**
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 4bc2a9b..658685f 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -286,11 +286,12 @@
      *
      * @param callId The callId to send the event for.
      * @param event The event.
+     * @param targetSdkVer Target sdk version of the app calling this api
      * @param extras Extras associated with the event.
      */
-    public void sendCallEvent(String callId, String event, Bundle extras) {
+    public void sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras) {
         try {
-            mAdapter.sendCallEvent(callId, event, extras);
+            mAdapter.sendCallEvent(callId, event, targetSdkVer, extras);
         } catch (RemoteException ignored) {
         }
     }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 2d1fe50..d292db3 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -236,6 +237,15 @@
             "android.telecom.extra.INCOMING_CALL_EXTRAS";
 
     /**
+     * Optional extra for {@link #ACTION_INCOMING_CALL} containing a boolean to indicate that the
+     * call has an externally generated ringer. Used by the HfpClientConnectionService when In Band
+     * Ringtone is enabled to prevent two ringers from being generated.
+     * @hide
+     */
+    public static final String EXTRA_CALL_EXTERNAL_RINGER =
+            "android.telecom.extra.CALL_EXTERNAL_RINGER";
+
+    /**
      * Optional extra for {@link android.content.Intent#ACTION_CALL} and
      * {@link android.content.Intent#ACTION_DIAL} {@code Intent} containing a {@link Bundle}
      * which contains metadata about the call. This {@link Bundle} will be saved into
@@ -1431,6 +1441,13 @@
     public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
         try {
             if (isServiceConnected()) {
+                if (extras != null && extras.getBoolean(EXTRA_IS_HANDOVER) &&
+                        mContext.getApplicationContext().getApplicationInfo().targetSdkVersion >
+                                Build.VERSION_CODES.O_MR1) {
+                    Log.e("TAG", "addNewIncomingCall failed. Use public api " +
+                            "acceptHandover for API > O-MR1");
+                    // TODO add "return" after DUO team adds support for new handover API
+                }
                 getTelecomService().addNewIncomingCall(
                         phoneAccount, extras == null ? new Bundle() : extras);
             }
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 23ac940..87ccd3e 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -64,7 +64,7 @@
 
     void pullExternalCall(String callId);
 
-    void sendCallEvent(String callId, String event, in Bundle extras);
+    void sendCallEvent(String callId, String event, int targetSdkVer, in Bundle extras);
 
     void putExtras(String callId, in Bundle extras);
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fccc2a6..ce0b551 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -337,6 +337,19 @@
             "notify_handover_video_from_wifi_to_lte_bool";
 
     /**
+     * Flag specifying whether the carrier wants to notify the user when a VT call has been handed
+     * over from LTE to WIFI.
+     * <p>
+     * The handover notification is sent as a
+     * {@link TelephonyManager#EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI}
+     * {@link android.telecom.Connection} event, which an {@link android.telecom.InCallService}
+     * should use to trigger the display of a user-facing message.
+     * @hide
+     */
+    public static final String KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL =
+            "notify_handover_video_from_lte_to_wifi_bool";
+
+    /**
      * Flag specifying whether the carrier supports downgrading a video call (tx, rx or tx/rx)
      * directly to an audio call.
      * @hide
@@ -947,8 +960,9 @@
     public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
 
     /**
-     * String to identify carrier name in CarrierConfig app. This string is used only if
-     * #KEY_CARRIER_NAME_OVERRIDE_BOOL is true
+     * String to identify carrier name in CarrierConfig app. This string overrides SPN if
+     * #KEY_CARRIER_NAME_OVERRIDE_BOOL is true; otherwise, it will be used if its value is provided
+     * and SPN is unavailable
      * @hide
      */
     public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
@@ -1740,6 +1754,13 @@
     public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL =
             "check_pricing_with_carrier_data_roaming_bool";
 
+    /**
+     * List of thresholds of RSRP for determining the display level of LTE signal bar.
+     * @hide
+     */
+    public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY =
+            "lte_rsrp_thresholds_int_array";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -1756,6 +1777,7 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false);
+        sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true);
         sDefaults.putString(KEY_DEFAULT_VM_NUMBER_STRING, "");
         sDefaults.putBoolean(KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL, false);
@@ -2028,6 +2050,15 @@
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
         sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
+        sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
+                new int[] {
+                        -140, /* SIGNAL_STRENGTH_NONE_OR_UNKNOWN */
+                        -128, /* SIGNAL_STRENGTH_POOR */
+                        -118, /* SIGNAL_STRENGTH_MODERATE */
+                        -108, /* SIGNAL_STRENGTH_GOOD */
+                        -98,  /* SIGNAL_STRENGTH_GREAT */
+                        -44
+                });
     }
 
     /**
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/telephony/java/android/telephony/CellIdentity.aidl
similarity index 90%
rename from telephony/java/android/telephony/data/InterfaceAddress.aidl
rename to telephony/java/android/telephony/CellIdentity.aidl
index d750363..aeee769 100644
--- a/telephony/java/android/telephony/data/InterfaceAddress.aidl
+++ b/telephony/java/android/telephony/CellIdentity.aidl
@@ -15,6 +15,6 @@
  */
 
 /** @hide */
-package android.telephony.data;
+package android.telephony;
 
-parcelable InterfaceAddress;
+parcelable CellIdentity;
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
new file mode 100644
index 0000000..e092d52
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.CallSuper;
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * CellIdentity represents the identity of a unique cell. This is the base class for
+ * CellIdentityXxx which represents cell identity for specific network access technology.
+ */
+public abstract class CellIdentity implements Parcelable {
+    /**
+     * Cell identity type
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "TYPE_", value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA})
+    public @interface Type {}
+
+    /**
+     * Unknown cell identity type
+     * @hide
+     */
+    public static final int TYPE_UNKNOWN        = 0;
+    /**
+     * GSM cell identity type
+     * @hide
+     */
+    public static final int TYPE_GSM            = 1;
+    /**
+     * CDMA cell identity type
+     * @hide
+     */
+    public static final int TYPE_CDMA           = 2;
+    /**
+     * LTE cell identity type
+     * @hide
+     */
+    public static final int TYPE_LTE            = 3;
+    /**
+     * WCDMA cell identity type
+     * @hide
+     */
+    public static final int TYPE_WCDMA          = 4;
+    /**
+     * TDS-CDMA cell identity type
+     * @hide
+     */
+    public static final int TYPE_TDSCDMA        = 5;
+
+    // Log tag
+    /** @hide */
+    protected final String mTag;
+    // Cell identity type
+    /** @hide */
+    protected final int mType;
+    // 3-digit Mobile Country Code in string format. Null for CDMA cell identity.
+    /** @hide */
+    protected final String mMccStr;
+    // 2 or 3-digit Mobile Network Code in string format. Null for CDMA cell identity.
+    /** @hide */
+    protected final String mMncStr;
+
+    /** @hide */
+    protected CellIdentity(String tag, int type, String mcc, String mnc) {
+        mTag = tag;
+        mType = type;
+
+        // Only allow INT_MAX if unknown string mcc/mnc
+        if (mcc == null || mcc.matches("^[0-9]{3}$")) {
+            mMccStr = mcc;
+        } else if (mcc.isEmpty() || mcc.equals(String.valueOf(Integer.MAX_VALUE))) {
+            // If the mccStr is empty or unknown, set it as null.
+            mMccStr = null;
+        } else {
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+            // after the bug got fixed.
+            mMccStr = null;
+            log("invalid MCC format: " + mcc);
+        }
+
+        if (mnc == null || mnc.matches("^[0-9]{2,3}$")) {
+            mMncStr = mnc;
+        } else if (mnc.isEmpty() || mnc.equals(String.valueOf(Integer.MAX_VALUE))) {
+            // If the mncStr is empty or unknown, set it as null.
+            mMncStr = null;
+        } else {
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+            // after the bug got fixed.
+            mMncStr = null;
+            log("invalid MNC format: " + mnc);
+        }
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * @hide
+     * @return The type of the cell identity
+     */
+    public @Type int getType() { return mType; }
+
+    /**
+     * Used by child classes for parceling.
+     *
+     * @hide
+     */
+    @CallSuper
+    public void writeToParcel(Parcel dest, int type) {
+        dest.writeInt(type);
+        dest.writeString(mMccStr);
+        dest.writeString(mMncStr);
+    }
+
+    /**
+     * Construct from Parcel
+     * @hide
+     */
+    protected CellIdentity(String tag, int type, Parcel source) {
+        this(tag, type, source.readString(), source.readString());
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<CellIdentity> CREATOR =
+            new Creator<CellIdentity>() {
+                @Override
+                public CellIdentity createFromParcel(Parcel in) {
+                    int type = in.readInt();
+                    switch (type) {
+                        case TYPE_GSM: return CellIdentityGsm.createFromParcelBody(in);
+                        case TYPE_WCDMA: return CellIdentityWcdma.createFromParcelBody(in);
+                        case TYPE_CDMA: return CellIdentityCdma.createFromParcelBody(in);
+                        case TYPE_LTE: return CellIdentityLte.createFromParcelBody(in);
+                        case TYPE_TDSCDMA: return CellIdentityTdscdma.createFromParcelBody(in);
+                        default: throw new IllegalArgumentException("Bad Cell identity Parcel");
+                    }
+                }
+
+                @Override
+                public CellIdentity[] newArray(int size) {
+                    return new CellIdentity[size];
+                }
+            };
+
+    /** @hide */
+    protected void log(String s) {
+        Rlog.w(mTag, s);
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index ddc938e..2e1d1dc 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -17,8 +17,6 @@
 package android.telephony;
 
 import android.os.Parcel;
-import android.os.Parcelable;
-import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import java.util.Objects;
@@ -26,9 +24,8 @@
 /**
  * CellIdentity is to represent a unique CDMA cell
  */
-public final class CellIdentityCdma implements Parcelable {
-
-    private static final String LOG_TAG = "CellSignalStrengthCdma";
+public final class CellIdentityCdma extends CellIdentity {
+    private static final String TAG = CellIdentityCdma.class.getSimpleName();
     private static final boolean DBG = false;
 
     // Network Id 0..65535
@@ -60,6 +57,7 @@
      * @hide
      */
     public CellIdentityCdma() {
+        super(TAG, TYPE_CDMA, null, null);
         mNetworkId = Integer.MAX_VALUE;
         mSystemId = Integer.MAX_VALUE;
         mBasestationId = Integer.MAX_VALUE;
@@ -81,7 +79,7 @@
      *
      * @hide
      */
-    public CellIdentityCdma (int nid, int sid, int bid, int lon, int lat) {
+    public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat) {
         this(nid, sid, bid, lon, lat, null, null);
     }
 
@@ -99,8 +97,9 @@
      *
      * @hide
      */
-    public CellIdentityCdma (int nid, int sid, int bid, int lon, int lat, String alphal,
+    public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat, String alphal,
                              String alphas) {
+        super(TAG, TYPE_CDMA, null, null);
         mNetworkId = nid;
         mSystemId = sid;
         mBasestationId = bid;
@@ -196,40 +195,33 @@
 
         CellIdentityCdma o = (CellIdentityCdma) other;
 
-        return mNetworkId == o.mNetworkId &&
-                mSystemId == o.mSystemId &&
-                mBasestationId == o.mBasestationId &&
-                mLatitude == o.mLatitude &&
-                mLongitude == o.mLongitude &&
-                TextUtils.equals(mAlphaLong, o.mAlphaLong) &&
-                TextUtils.equals(mAlphaShort, o.mAlphaShort);
+        return mNetworkId == o.mNetworkId
+                && mSystemId == o.mSystemId
+                && mBasestationId == o.mBasestationId
+                && mLatitude == o.mLatitude
+                && mLongitude == o.mLongitude
+                && TextUtils.equals(mAlphaLong, o.mAlphaLong)
+                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
     }
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentityCdma:{");
-        sb.append(" mNetworkId="); sb.append(mNetworkId);
-        sb.append(" mSystemId="); sb.append(mSystemId);
-        sb.append(" mBasestationId="); sb.append(mBasestationId);
-        sb.append(" mLongitude="); sb.append(mLongitude);
-        sb.append(" mLatitude="); sb.append(mLatitude);
-        sb.append(" mAlphaLong="); sb.append(mAlphaLong);
-        sb.append(" mAlphaShort="); sb.append(mAlphaShort);
-        sb.append("}");
-
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface */
-    @Override
-    public int describeContents() {
-        return 0;
+        return new StringBuilder(TAG)
+        .append(":{ mNetworkId=").append(mNetworkId)
+        .append(" mSystemId=").append(mSystemId)
+        .append(" mBasestationId=").append(mBasestationId)
+        .append(" mLongitude=").append(mLongitude)
+        .append(" mLatitude=").append(mLatitude)
+        .append(" mAlphaLong=").append(mAlphaLong)
+        .append(" mAlphaShort=").append(mAlphaShort)
+        .append("}").toString();
     }
 
     /** Implement the Parcelable interface */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        super.writeToParcel(dest, TYPE_CDMA);
         dest.writeInt(mNetworkId);
         dest.writeInt(mSystemId);
         dest.writeInt(mBasestationId);
@@ -241,10 +233,16 @@
 
     /** Construct from Parcel, type has already been processed */
     private CellIdentityCdma(Parcel in) {
-        this(in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readInt(),
-                in.readString(), in.readString());
+        super(TAG, TYPE_CDMA, in);
+        mNetworkId = in.readInt();
+        mSystemId = in.readInt();
+        mBasestationId = in.readInt();
+        mLongitude = in.readInt();
+        mLatitude = in.readInt();
+        mAlphaLong = in.readString();
+        mAlphaShort = in.readString();
 
-        if (DBG) log("CellIdentityCdma(Parcel): " + toString());
+        if (DBG) log(toString());
     }
 
     /** Implement the Parcelable interface */
@@ -253,7 +251,8 @@
             new Creator<CellIdentityCdma>() {
         @Override
         public CellIdentityCdma createFromParcel(Parcel in) {
-            return new CellIdentityCdma(in);
+            in.readInt();   // skip
+            return createFromParcelBody(in);
         }
 
         @Override
@@ -262,10 +261,8 @@
         }
     };
 
-    /**
-     * log
-     */
-    private static void log(String s) {
-        Rlog.w(LOG_TAG, s);
+    /** @hide */
+    protected static CellIdentityCdma createFromParcelBody(Parcel in) {
+        return new CellIdentityCdma(in);
     }
 }
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 376e6aa..f948f81 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -17,8 +17,6 @@
 package android.telephony;
 
 import android.os.Parcel;
-import android.os.Parcelable;
-import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import java.util.Objects;
@@ -26,9 +24,8 @@
 /**
  * CellIdentity to represent a unique GSM cell
  */
-public final class CellIdentityGsm implements Parcelable {
-
-    private static final String LOG_TAG = "CellIdentityGsm";
+public final class CellIdentityGsm extends CellIdentity {
+    private static final String TAG = CellIdentityGsm.class.getSimpleName();
     private static final boolean DBG = false;
 
     // 16-bit Location Area Code, 0..65535
@@ -39,10 +36,6 @@
     private final int mArfcn;
     // 6-bit Base Station Identity Code
     private final int mBsic;
-    // 3-digit Mobile Country Code in string format
-    private final String mMccStr;
-    // 2 or 3-digit Mobile Network Code in string format
-    private final String mMncStr;
     // long alpha Operator Name String or Enhanced Operator Name String
     private final String mAlphaLong;
     // short alpha Operator Name String or Enhanced Operator Name String
@@ -52,12 +45,11 @@
      * @hide
      */
     public CellIdentityGsm() {
+        super(TAG, TYPE_GSM, null, null);
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mArfcn = Integer.MAX_VALUE;
         mBsic = Integer.MAX_VALUE;
-        mMccStr = null;
-        mMncStr = null;
         mAlphaLong = null;
         mAlphaShort = null;
     }
@@ -70,7 +62,7 @@
      *
      * @hide
      */
-    public CellIdentityGsm (int mcc, int mnc, int lac, int cid) {
+    public CellIdentityGsm(int mcc, int mnc, int lac, int cid) {
         this(lac, cid, Integer.MAX_VALUE, Integer.MAX_VALUE,
                 String.valueOf(mcc), String.valueOf(mnc), null, null);
     }
@@ -86,7 +78,7 @@
      *
      * @hide
      */
-    public CellIdentityGsm (int mcc, int mnc, int lac, int cid, int arfcn, int bsic) {
+    public CellIdentityGsm(int mcc, int mnc, int lac, int cid, int arfcn, int bsic) {
         this(lac, cid, arfcn, bsic, String.valueOf(mcc), String.valueOf(mnc), null, null);
     }
 
@@ -103,8 +95,9 @@
      *
      * @hide
      */
-    public CellIdentityGsm (int lac, int cid, int arfcn, int bsic, String mccStr,
+    public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr,
                             String mncStr, String alphal, String alphas) {
+        super(TAG, TYPE_GSM, mccStr, mncStr);
         mLac = lac;
         mCid = cid;
         mArfcn = arfcn;
@@ -112,31 +105,6 @@
         // for inbound parcels
         mBsic = (bsic == 0xFF) ? Integer.MAX_VALUE : bsic;
 
-        // Only allow INT_MAX if unknown string mcc/mnc
-        if (mccStr == null || mccStr.matches("^[0-9]{3}$")) {
-            mMccStr = mccStr;
-        } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) {
-            // If the mccStr is empty or unknown, set it as null.
-            mMccStr = null;
-        } else {
-            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
-            // after the bug got fixed.
-            mMccStr = null;
-            log("invalid MCC format: " + mccStr);
-        }
-
-        if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
-            mMncStr = mncStr;
-        } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) {
-            // If the mncStr is empty or unknown, set it as null.
-            mMncStr = null;
-        } else {
-            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
-            // after the bug got fixed.
-            mMncStr = null;
-            log("invalid MNC format: " + mncStr);
-        }
-
         mAlphaLong = alphal;
         mAlphaShort = alphas;
     }
@@ -237,6 +205,7 @@
 
 
     /**
+     * @deprecated Primary Scrambling Code is not applicable to GSM.
      * @return Integer.MAX_VALUE, undefined for GSM
      */
     @Deprecated
@@ -260,58 +229,54 @@
         }
 
         CellIdentityGsm o = (CellIdentityGsm) other;
-        return mLac == o.mLac &&
-                mCid == o.mCid &&
-                mArfcn == o.mArfcn &&
-                mBsic == o.mBsic &&
-                TextUtils.equals(mMccStr, o.mMccStr) &&
-                TextUtils.equals(mMncStr, o.mMncStr) &&
-                TextUtils.equals(mAlphaLong, o.mAlphaLong) &&
-                TextUtils.equals(mAlphaShort, o.mAlphaShort);
+        return mLac == o.mLac
+                && mCid == o.mCid
+                && mArfcn == o.mArfcn
+                && mBsic == o.mBsic
+                && TextUtils.equals(mMccStr, o.mMccStr)
+                && TextUtils.equals(mMncStr, o.mMncStr)
+                && TextUtils.equals(mAlphaLong, o.mAlphaLong)
+                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
     }
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentityGsm:{");
-        sb.append(" mLac=").append(mLac);
-        sb.append(" mCid=").append(mCid);
-        sb.append(" mArfcn=").append(mArfcn);
-        sb.append(" mBsic=").append("0x").append(Integer.toHexString(mBsic));
-        sb.append(" mMcc=").append(mMccStr);
-        sb.append(" mMnc=").append(mMncStr);
-        sb.append(" mAlphaLong=").append(mAlphaLong);
-        sb.append(" mAlphaShort=").append(mAlphaShort);
-        sb.append("}");
-
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface */
-    @Override
-    public int describeContents() {
-        return 0;
+        return new StringBuilder(TAG)
+        .append(":{ mLac=").append(mLac)
+        .append(" mCid=").append(mCid)
+        .append(" mArfcn=").append(mArfcn)
+        .append(" mBsic=").append("0x").append(Integer.toHexString(mBsic))
+        .append(" mMcc=").append(mMccStr)
+        .append(" mMnc=").append(mMncStr)
+        .append(" mAlphaLong=").append(mAlphaLong)
+        .append(" mAlphaShort=").append(mAlphaShort)
+        .append("}").toString();
     }
 
     /** Implement the Parcelable interface */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        super.writeToParcel(dest, TYPE_GSM);
         dest.writeInt(mLac);
         dest.writeInt(mCid);
         dest.writeInt(mArfcn);
         dest.writeInt(mBsic);
-        dest.writeString(mMccStr);
-        dest.writeString(mMncStr);
         dest.writeString(mAlphaLong);
         dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
     private CellIdentityGsm(Parcel in) {
-        this(in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readString(),
-                in.readString(), in.readString(), in.readString());
+        super(TAG, TYPE_GSM, in);
+        mLac = in.readInt();
+        mCid = in.readInt();
+        mArfcn = in.readInt();
+        mBsic = in.readInt();
+        mAlphaLong = in.readString();
+        mAlphaShort = in.readString();
 
-        if (DBG) log("CellIdentityGsm(Parcel): " + toString());
+        if (DBG) log(toString());
     }
 
     /** Implement the Parcelable interface */
@@ -320,7 +285,8 @@
             new Creator<CellIdentityGsm>() {
                 @Override
                 public CellIdentityGsm createFromParcel(Parcel in) {
-                    return new CellIdentityGsm(in);
+                    in.readInt();   // skip
+                    return createFromParcelBody(in);
                 }
 
                 @Override
@@ -329,10 +295,8 @@
                 }
             };
 
-    /**
-     * log
-     */
-    private static void log(String s) {
-        Rlog.w(LOG_TAG, s);
+    /** @hide */
+    protected static CellIdentityGsm createFromParcelBody(Parcel in) {
+        return new CellIdentityGsm(in);
     }
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 6ca5daf6..7f20c8a 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -17,8 +17,6 @@
 package android.telephony;
 
 import android.os.Parcel;
-import android.os.Parcelable;
-import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import java.util.Objects;
@@ -26,9 +24,8 @@
 /**
  * CellIdentity is to represent a unique LTE cell
  */
-public final class CellIdentityLte implements Parcelable {
-
-    private static final String LOG_TAG = "CellIdentityLte";
+public final class CellIdentityLte extends CellIdentity {
+    private static final String TAG = CellIdentityLte.class.getSimpleName();
     private static final boolean DBG = false;
 
     // 28-bit cell identity
@@ -39,10 +36,6 @@
     private final int mTac;
     // 18-bit Absolute RF Channel Number
     private final int mEarfcn;
-    // 3-digit Mobile Country Code in string format
-    private final String mMccStr;
-    // 2 or 3-digit Mobile Network Code in string format
-    private final String mMncStr;
     // long alpha Operator Name String or Enhanced Operator Name String
     private final String mAlphaLong;
     // short alpha Operator Name String or Enhanced Operator Name String
@@ -52,12 +45,11 @@
      * @hide
      */
     public CellIdentityLte() {
+        super(TAG, TYPE_LTE, null, null);
         mCi = Integer.MAX_VALUE;
         mPci = Integer.MAX_VALUE;
         mTac = Integer.MAX_VALUE;
         mEarfcn = Integer.MAX_VALUE;
-        mMccStr = null;
-        mMncStr = null;
         mAlphaLong = null;
         mAlphaShort = null;
     }
@@ -72,7 +64,7 @@
      *
      * @hide
      */
-    public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac) {
+    public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac) {
         this(ci, pci, tac, Integer.MAX_VALUE, String.valueOf(mcc), String.valueOf(mnc), null, null);
     }
 
@@ -87,7 +79,7 @@
      *
      * @hide
      */
-    public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac, int earfcn) {
+    public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac, int earfcn) {
         this(ci, pci, tac, earfcn, String.valueOf(mcc), String.valueOf(mnc), null, null);
     }
 
@@ -104,38 +96,13 @@
      *
      * @hide
      */
-    public CellIdentityLte (int ci, int pci, int tac, int earfcn, String mccStr,
+    public CellIdentityLte(int ci, int pci, int tac, int earfcn, String mccStr,
                             String mncStr, String alphal, String alphas) {
+        super(TAG, TYPE_LTE, mccStr, mncStr);
         mCi = ci;
         mPci = pci;
         mTac = tac;
         mEarfcn = earfcn;
-
-        // Only allow INT_MAX if unknown string mcc/mnc
-        if (mccStr == null || mccStr.matches("^[0-9]{3}$")) {
-            mMccStr = mccStr;
-        } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) {
-            // If the mccStr is empty or unknown, set it as null.
-            mMccStr = null;
-        } else {
-            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
-            // after the bug got fixed.
-            mMccStr = null;
-            log("invalid MCC format: " + mccStr);
-        }
-
-        if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
-            mMncStr = mncStr;
-        } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) {
-            // If the mncStr is empty or unknown, set it as null.
-            mMncStr = null;
-        } else {
-            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
-            // after the bug got fixed.
-            mMncStr = null;
-            log("invalid MNC format: " + mncStr);
-        }
-
         mAlphaLong = alphal;
         mAlphaShort = alphas;
     }
@@ -248,58 +215,54 @@
         }
 
         CellIdentityLte o = (CellIdentityLte) other;
-        return mCi == o.mCi &&
-                mPci == o.mPci &&
-                mTac == o.mTac &&
-                mEarfcn == o.mEarfcn &&
-                TextUtils.equals(mMccStr, o.mMccStr) &&
-                TextUtils.equals(mMncStr, o.mMncStr) &&
-                TextUtils.equals(mAlphaLong, o.mAlphaLong) &&
-                TextUtils.equals(mAlphaShort, o.mAlphaShort);
+        return mCi == o.mCi
+                && mPci == o.mPci
+                && mTac == o.mTac
+                && mEarfcn == o.mEarfcn
+                && TextUtils.equals(mMccStr, o.mMccStr)
+                && TextUtils.equals(mMncStr, o.mMncStr)
+                && TextUtils.equals(mAlphaLong, o.mAlphaLong)
+                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
     }
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentityLte:{");
-        sb.append(" mCi="); sb.append(mCi);
-        sb.append(" mPci="); sb.append(mPci);
-        sb.append(" mTac="); sb.append(mTac);
-        sb.append(" mEarfcn="); sb.append(mEarfcn);
-        sb.append(" mMcc="); sb.append(mMccStr);
-        sb.append(" mMnc="); sb.append(mMncStr);
-        sb.append(" mAlphaLong="); sb.append(mAlphaLong);
-        sb.append(" mAlphaShort="); sb.append(mAlphaShort);
-        sb.append("}");
-
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface */
-    @Override
-    public int describeContents() {
-        return 0;
+        return new StringBuilder(TAG)
+        .append(":{ mCi=").append(mCi)
+        .append(" mPci=").append(mPci)
+        .append(" mTac=").append(mTac)
+        .append(" mEarfcn=").append(mEarfcn)
+        .append(" mMcc=").append(mMccStr)
+        .append(" mMnc=").append(mMncStr)
+        .append(" mAlphaLong=").append(mAlphaLong)
+        .append(" mAlphaShort=").append(mAlphaShort)
+        .append("}").toString();
     }
 
     /** Implement the Parcelable interface */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        super.writeToParcel(dest, TYPE_LTE);
         dest.writeInt(mCi);
         dest.writeInt(mPci);
         dest.writeInt(mTac);
         dest.writeInt(mEarfcn);
-        dest.writeString(mMccStr);
-        dest.writeString(mMncStr);
         dest.writeString(mAlphaLong);
         dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
     private CellIdentityLte(Parcel in) {
-        this(in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readString(),
-                in.readString(), in.readString(), in.readString());
+        super(TAG, TYPE_LTE, in);
+        mCi = in.readInt();
+        mPci = in.readInt();
+        mTac = in.readInt();
+        mEarfcn = in.readInt();
+        mAlphaLong = in.readString();
+        mAlphaShort = in.readString();
 
-        if (DBG) log("CellIdentityLte(Parcel): " + toString());
+        if (DBG) log(toString());
     }
 
     /** Implement the Parcelable interface */
@@ -308,7 +271,8 @@
             new Creator<CellIdentityLte>() {
                 @Override
                 public CellIdentityLte createFromParcel(Parcel in) {
-                    return new CellIdentityLte(in);
+                    in.readInt();   // skip;
+                    return createFromParcelBody(in);
                 }
 
                 @Override
@@ -317,10 +281,8 @@
                 }
             };
 
-    /**
-     * log
-     */
-    private static void log(String s) {
-        Rlog.w(LOG_TAG, s);
+    /** @hide */
+    protected static CellIdentityLte createFromParcelBody(Parcel in) {
+        return new CellIdentityLte(in);
     }
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/telephony/java/android/telephony/CellIdentityTdscdma.aidl
similarity index 90%
copy from telephony/java/android/telephony/data/InterfaceAddress.aidl
copy to telephony/java/android/telephony/CellIdentityTdscdma.aidl
index d750363..2a182cd 100644
--- a/telephony/java/android/telephony/data/InterfaceAddress.aidl
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.aidl
@@ -15,6 +15,6 @@
  */
 
 /** @hide */
-package android.telephony.data;
+package android.telephony;
 
-parcelable InterfaceAddress;
+parcelable CellIdentityTdscdma;
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
new file mode 100644
index 0000000..001d19f
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+/**
+ * CellIdentity is to represent a unique TD-SCDMA cell
+ */
+public final class CellIdentityTdscdma extends CellIdentity {
+    private static final String TAG = CellIdentityTdscdma.class.getSimpleName();
+    private static final boolean DBG = false;
+
+    // 16-bit Location Area Code, 0..65535, INT_MAX if unknown.
+    private final int mLac;
+    // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown.
+    private final int mCid;
+    // 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown.
+    private final int mCpid;
+
+    /**
+     * @hide
+     */
+    public CellIdentityTdscdma() {
+        super(TAG, TYPE_TDSCDMA, null, null);
+        mLac = Integer.MAX_VALUE;
+        mCid = Integer.MAX_VALUE;
+        mCpid = Integer.MAX_VALUE;
+    }
+
+    /**
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param lac 16-bit Location Area Code, 0..65535, INT_MAX if unknown
+     * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
+     * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
+     *
+     * @hide
+     */
+    public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid) {
+        this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid);
+    }
+
+    /**
+     * @param mcc 3-digit Mobile Country Code in string format
+     * @param mnc 2 or 3-digit Mobile Network Code in string format
+     * @param lac 16-bit Location Area Code, 0..65535, INT_MAX if unknown
+     * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
+     * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
+     *
+     * @hide
+     */
+    public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) {
+        super(TAG, TYPE_TDSCDMA, mcc, mnc);
+        mLac = lac;
+        mCid = cid;
+        mCpid = cpid;
+    }
+
+    private CellIdentityTdscdma(CellIdentityTdscdma cid) {
+        this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, cid.mCpid);
+    }
+
+    CellIdentityTdscdma copy() {
+        return new CellIdentityTdscdma(this);
+    }
+
+    /**
+     * Get Mobile Country Code in string format
+     * @return Mobile Country Code in string format, null if unknown
+     */
+    public String getMccStr() {
+        return mMccStr;
+    }
+
+    /**
+     * Get Mobile Network Code in string format
+     * @return Mobile Network Code in string format, null if unknown
+     */
+    public String getMncStr() {
+        return mMncStr;
+    }
+
+    /**
+     * @return 16-bit Location Area Code, 0..65535, INT_MAX if unknown
+     */
+    public int getLac() {
+        return mLac;
+    }
+
+    /**
+     * @return 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
+     */
+    public int getCid() {
+        return mCid;
+    }
+
+    /**
+     * @return 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
+     */
+    public int getCpid() {
+        return mCpid;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof CellIdentityTdscdma)) {
+            return false;
+        }
+
+        CellIdentityTdscdma o = (CellIdentityTdscdma) other;
+        return TextUtils.equals(mMccStr, o.mMccStr)
+                && TextUtils.equals(mMncStr, o.mMncStr)
+                && mLac == o.mLac
+                && mCid == o.mCid
+                && mCpid == o.mCpid;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder(TAG)
+        .append(":{ mMcc=").append(mMccStr)
+        .append(" mMnc=").append(mMncStr)
+        .append(" mLac=").append(mLac)
+        .append(" mCid=").append(mCid)
+        .append(" mCpid=").append(mCpid)
+        .append("}").toString();
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        super.writeToParcel(dest, TYPE_TDSCDMA);
+        dest.writeInt(mLac);
+        dest.writeInt(mCid);
+        dest.writeInt(mCpid);
+    }
+
+    /** Construct from Parcel, type has already been processed */
+    private CellIdentityTdscdma(Parcel in) {
+        super(TAG, TYPE_TDSCDMA, in);
+        mLac = in.readInt();
+        mCid = in.readInt();
+        mCpid = in.readInt();
+
+        if (DBG) log(toString());
+    }
+
+    /** Implement the Parcelable interface */
+    @SuppressWarnings("hiding")
+    public static final Creator<CellIdentityTdscdma> CREATOR =
+            new Creator<CellIdentityTdscdma>() {
+                @Override
+                public CellIdentityTdscdma createFromParcel(Parcel in) {
+                    in.readInt();   // skip
+                    return createFromParcelBody(in);
+                }
+
+                @Override
+                public CellIdentityTdscdma[] newArray(int size) {
+                    return new CellIdentityTdscdma[size];
+                }
+            };
+
+    /** @hide */
+    protected static CellIdentityTdscdma createFromParcelBody(Parcel in) {
+        return new CellIdentityTdscdma(in);
+    }
+}
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index e4bb4f2..1aa1715 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -17,8 +17,6 @@
 package android.telephony;
 
 import android.os.Parcel;
-import android.os.Parcelable;
-import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import java.util.Objects;
@@ -26,9 +24,8 @@
 /**
  * CellIdentity to represent a unique UMTS cell
  */
-public final class CellIdentityWcdma implements Parcelable {
-
-    private static final String LOG_TAG = "CellIdentityWcdma";
+public final class CellIdentityWcdma extends CellIdentity {
+    private static final String TAG = CellIdentityWcdma.class.getSimpleName();
     private static final boolean DBG = false;
 
     // 16-bit Location Area Code, 0..65535
@@ -39,10 +36,6 @@
     private final int mPsc;
     // 16-bit UMTS Absolute RF Channel Number
     private final int mUarfcn;
-    // 3-digit Mobile Country Code in string format
-    private final String mMccStr;
-    // 2 or 3-digit Mobile Network Code in string format
-    private final String mMncStr;
     // long alpha Operator Name String or Enhanced Operator Name String
     private final String mAlphaLong;
     // short alpha Operator Name String or Enhanced Operator Name String
@@ -52,12 +45,11 @@
      * @hide
      */
     public CellIdentityWcdma() {
+        super(TAG, TYPE_TDSCDMA, null, null);
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mPsc = Integer.MAX_VALUE;
         mUarfcn = Integer.MAX_VALUE;
-        mMccStr = null;
-        mMncStr = null;
         mAlphaLong = null;
         mAlphaShort = null;
     }
@@ -106,36 +98,11 @@
      */
     public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn,
                               String mccStr, String mncStr, String alphal, String alphas) {
+        super(TAG, TYPE_WCDMA, mccStr, mncStr);
         mLac = lac;
         mCid = cid;
         mPsc = psc;
         mUarfcn = uarfcn;
-
-        // Only allow INT_MAX if unknown string mcc/mnc
-        if (mccStr == null || mccStr.matches("^[0-9]{3}$")) {
-            mMccStr = mccStr;
-        } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) {
-            // If the mccStr is empty or unknown, set it as null.
-            mMccStr = null;
-        } else {
-            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
-            // after the bug got fixed.
-            mMccStr = null;
-            log("invalid MCC format: " + mccStr);
-        }
-
-        if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
-            mMncStr = mncStr;
-        } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) {
-            // If the mncStr is empty or unknown, set it as null.
-            mMncStr = null;
-        } else {
-            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
-            // after the bug got fixed.
-            mMncStr = null;
-            log("invalid MNC format: " + mncStr);
-        }
-
         mAlphaLong = alphal;
         mAlphaShort = alphas;
     }
@@ -250,58 +217,53 @@
         }
 
         CellIdentityWcdma o = (CellIdentityWcdma) other;
-        return mLac == o.mLac &&
-                mCid == o.mCid &&
-                mPsc == o.mPsc &&
-                mUarfcn == o.mUarfcn &&
-                TextUtils.equals(mMccStr, o.mMccStr) &&
-                TextUtils.equals(mMncStr, o.mMncStr) &&
-                TextUtils.equals(mAlphaLong, o.mAlphaLong) &&
-                TextUtils.equals(mAlphaShort, o.mAlphaShort);
+        return mLac == o.mLac
+                && mCid == o.mCid
+                && mPsc == o.mPsc
+                && mUarfcn == o.mUarfcn
+                && TextUtils.equals(mMccStr, o.mMccStr)
+                && TextUtils.equals(mMncStr, o.mMncStr)
+                && TextUtils.equals(mAlphaLong, o.mAlphaLong)
+                && TextUtils.equals(mAlphaShort, o.mAlphaShort);
     }
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentityWcdma:{");
-        sb.append(" mLac=").append(mLac);
-        sb.append(" mCid=").append(mCid);
-        sb.append(" mPsc=").append(mPsc);
-        sb.append(" mUarfcn=").append(mUarfcn);
-        sb.append(" mMcc=").append(mMccStr);
-        sb.append(" mMnc=").append(mMncStr);
-        sb.append(" mAlphaLong=").append(mAlphaLong);
-        sb.append(" mAlphaShort=").append(mAlphaShort);
-        sb.append("}");
-
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface */
-    @Override
-    public int describeContents() {
-        return 0;
+        return new StringBuilder(TAG)
+        .append(":{ mLac=").append(mLac)
+        .append(" mCid=").append(mCid)
+        .append(" mPsc=").append(mPsc)
+        .append(" mUarfcn=").append(mUarfcn)
+        .append(" mMcc=").append(mMccStr)
+        .append(" mMnc=").append(mMncStr)
+        .append(" mAlphaLong=").append(mAlphaLong)
+        .append(" mAlphaShort=").append(mAlphaShort)
+        .append("}").toString();
     }
 
     /** Implement the Parcelable interface */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        super.writeToParcel(dest, TYPE_WCDMA);
         dest.writeInt(mLac);
         dest.writeInt(mCid);
         dest.writeInt(mPsc);
         dest.writeInt(mUarfcn);
-        dest.writeString(mMccStr);
-        dest.writeString(mMncStr);
         dest.writeString(mAlphaLong);
         dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
     private CellIdentityWcdma(Parcel in) {
-        this(in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readString(),
-                in.readString(), in.readString(), in.readString());
-
-        if (DBG) log("CellIdentityWcdma(Parcel): " + toString());
+        super(TAG, TYPE_WCDMA, in);
+        mLac = in.readInt();
+        mCid = in.readInt();
+        mPsc = in.readInt();
+        mUarfcn = in.readInt();
+        mAlphaLong = in.readString();
+        mAlphaShort = in.readString();
+        if (DBG) log(toString());
     }
 
     /** Implement the Parcelable interface */
@@ -310,7 +272,8 @@
             new Creator<CellIdentityWcdma>() {
                 @Override
                 public CellIdentityWcdma createFromParcel(Parcel in) {
-                    return new CellIdentityWcdma(in);
+                    in.readInt();   // skip
+                    return createFromParcelBody(in);
                 }
 
                 @Override
@@ -319,10 +282,8 @@
                 }
             };
 
-    /**
-     * log
-     */
-    private static void log(String s) {
-        Rlog.w(LOG_TAG, s);
+    /** @hide */
+    protected static CellIdentityWcdma createFromParcelBody(Parcel in) {
+        return new CellIdentityWcdma(in);
     }
 }
\ No newline at end of file
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index c7e5131..98ea451 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -244,6 +244,13 @@
      */
     public static final int LISTEN_DATA_ACTIVATION_STATE                   = 0x00040000;
 
+    /**
+     *  Listen for changes to the user mobile data state
+     *
+     *  @see #onUserMobileDataStateChanged
+     */
+    public static final int LISTEN_USER_MOBILE_DATA_STATE                  = 0x00080000;
+
      /*
      * Subscription used to listen to the phone state changes
      * @hide
@@ -349,6 +356,9 @@
                     case LISTEN_DATA_ACTIVATION_STATE:
                         PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj);
                         break;
+                    case LISTEN_USER_MOBILE_DATA_STATE:
+                        PhoneStateListener.this.onUserMobileDataStateChanged((boolean)msg.obj);
+                        break;
                     case LISTEN_CARRIER_NETWORK_CHANGE:
                         PhoneStateListener.this.onCarrierNetworkChange((boolean)msg.obj);
                         break;
@@ -543,6 +553,14 @@
     }
 
     /**
+     * Callback invoked when the user mobile data state has changed
+     * @param enabled indicates whether the current user mobile data state is enabled or disabled.
+     */
+    public void onUserMobileDataStateChanged(boolean enabled) {
+        // default implementation empty
+    }
+
+    /**
      * Callback invoked when telephony has received notice from a carrier
      * app that a network action that could result in connectivity loss
      * has been requested by an app using
@@ -654,6 +672,10 @@
             send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState);
         }
 
+        public void onUserMobileDataStateChanged(boolean enabled) {
+            send(LISTEN_USER_MOBILE_DATA_STATE, 0, 0, enabled);
+        }
+
         public void onCarrierNetworkChange(boolean active) {
             send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active);
         }
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index de02de7..d2134f9 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -19,9 +19,13 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.CarrierConfigManager;
 import android.util.Log;
 import android.content.res.Resources;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+
 /**
  * Contains phone signal strength related information.
  */
@@ -51,6 +55,8 @@
     //Use int max, as -1 is a valid value in signal strength
     public static final int INVALID = 0x7FFFFFFF;
 
+    private static final int LTE_RSRP_THRESHOLDS_NUM = 6;
+
     private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mGsmBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
     private int mCdmaDbm;   // This value is the RSSI value
@@ -70,6 +76,9 @@
     private boolean isGsm; // This value is set by the ServiceStateTracker onSignalStrengthResult
     private boolean mUseOnlyRsrpForLteLevel; // Use only RSRP for the number of LTE signal bar.
 
+    // The threshold of LTE RSRP for determining the display level of LTE signal bar.
+    private int mLteRsrpThresholds[] = new int[LTE_RSRP_THRESHOLDS_NUM];
+
     /**
      * Create a new SignalStrength from a intent notifier Bundle
      *
@@ -110,6 +119,7 @@
         mTdScdmaRscp = INVALID;
         isGsm = true;
         mUseOnlyRsrpForLteLevel = false;
+        setLteRsrpThresholds(getDefaultLteRsrpThresholds());
     }
 
     /**
@@ -137,6 +147,7 @@
         mTdScdmaRscp = INVALID;
         isGsm = gsmFlag;
         mUseOnlyRsrpForLteLevel = false;
+        setLteRsrpThresholds(getDefaultLteRsrpThresholds());
     }
 
     /**
@@ -276,6 +287,8 @@
         mTdScdmaRscp = INVALID;
         isGsm = gsm;
         mUseOnlyRsrpForLteLevel = useOnlyRsrpForLteLevel;
+
+        setLteRsrpThresholds(getDefaultLteRsrpThresholds());
         if (DBG) log("initialize: " + toString());
     }
 
@@ -299,6 +312,7 @@
         mTdScdmaRscp = s.mTdScdmaRscp;
         isGsm = s.isGsm;
         mUseOnlyRsrpForLteLevel = s.mUseOnlyRsrpForLteLevel;
+        setLteRsrpThresholds(s.mLteRsrpThresholds);
     }
 
     /**
@@ -325,6 +339,9 @@
         mTdScdmaRscp = in.readInt();
         isGsm = (in.readInt() != 0);
         mUseOnlyRsrpForLteLevel = (in.readInt() != 0);
+        for (int i = 0; i < LTE_RSRP_THRESHOLDS_NUM; i++) {
+            mLteRsrpThresholds[i] = in.readInt();
+        }
     }
 
     /**
@@ -374,6 +391,9 @@
         out.writeInt(mTdScdmaRscp);
         out.writeInt(isGsm ? 1 : 0);
         out.writeInt(mUseOnlyRsrpForLteLevel ? 1 : 0);
+        for (int i = 0; i < LTE_RSRP_THRESHOLDS_NUM; i++) {
+            out.writeInt(mLteRsrpThresholds[i]);
+        }
     }
 
     /**
@@ -480,6 +500,22 @@
     }
 
     /**
+     * Sets the threshold array for determining the display level of LTE signal bar.
+     *
+     * @param lteRsrpThresholds int array for determining the display level.
+     *
+     * @hide
+     */
+    public void setLteRsrpThresholds(int[] lteRsrpThresholds) {
+        if ((lteRsrpThresholds == null)
+                || (lteRsrpThresholds.length != LTE_RSRP_THRESHOLDS_NUM)) {
+            Log.wtf(LOG_TAG, "setLteRsrpThresholds - lteRsrpThresholds is invalid.");
+            return;
+        }
+        System.arraycopy(lteRsrpThresholds, 0, mLteRsrpThresholds, 0, LTE_RSRP_THRESHOLDS_NUM);
+    }
+
+    /**
      * Get the GSM Signal Strength, valid values are (0-31, 99) as defined in TS
      * 27.007 8.5
      */
@@ -833,25 +869,18 @@
          */
         int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1;
 
-        int[] threshRsrp = Resources.getSystem().getIntArray(
-                com.android.internal.R.array.config_lteDbmThresholds);
-        if (threshRsrp.length != 6) {
-            Log.wtf(LOG_TAG, "getLteLevel - config_lteDbmThresholds has invalid num of elements."
-                    + " Cannot evaluate RSRP signal.");
-        } else {
-            if (mLteRsrp > threshRsrp[5]) {
-                rsrpIconLevel = -1;
-            } else if (mLteRsrp >= (threshRsrp[4] - mLteRsrpBoost)) {
-                rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
-            } else if (mLteRsrp >= (threshRsrp[3] - mLteRsrpBoost)) {
-                rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
-            } else if (mLteRsrp >= (threshRsrp[2] - mLteRsrpBoost)) {
-                rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
-            } else if (mLteRsrp >= (threshRsrp[1] - mLteRsrpBoost)) {
-                rsrpIconLevel = SIGNAL_STRENGTH_POOR;
-            } else if (mLteRsrp >= threshRsrp[0]) {
-                rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-            }
+        if (mLteRsrp > mLteRsrpThresholds[5]) {
+            rsrpIconLevel = -1;
+        } else if (mLteRsrp >= (mLteRsrpThresholds[4] - mLteRsrpBoost)) {
+            rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
+        } else if (mLteRsrp >= (mLteRsrpThresholds[3] - mLteRsrpBoost)) {
+            rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
+        } else if (mLteRsrp >= (mLteRsrpThresholds[2] - mLteRsrpBoost)) {
+            rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
+        } else if (mLteRsrp >= (mLteRsrpThresholds[1] - mLteRsrpBoost)) {
+            rsrpIconLevel = SIGNAL_STRENGTH_POOR;
+        } else if (mLteRsrp >= mLteRsrpThresholds[0]) {
+            rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
         }
 
         if (useOnlyRsrpForLteLevel()) {
@@ -1010,7 +1039,7 @@
                 + (mLteSignalStrength * primeNum) + (mLteRsrp * primeNum)
                 + (mLteRsrq * primeNum) + (mLteRssnr * primeNum) + (mLteCqi * primeNum)
                 + (mLteRsrpBoost * primeNum) + (mTdScdmaRscp * primeNum) + (isGsm ? 1 : 0)
-                + (mUseOnlyRsrpForLteLevel ? 1 : 0));
+                + (mUseOnlyRsrpForLteLevel ? 1 : 0) + (Arrays.hashCode(mLteRsrpThresholds)));
     }
 
     /**
@@ -1045,7 +1074,8 @@
                 && mLteRsrpBoost == s.mLteRsrpBoost
                 && mTdScdmaRscp == s.mTdScdmaRscp
                 && isGsm == s.isGsm
-                && mUseOnlyRsrpForLteLevel == s.mUseOnlyRsrpForLteLevel);
+                && mUseOnlyRsrpForLteLevel == s.mUseOnlyRsrpForLteLevel
+                && Arrays.equals(mLteRsrpThresholds, s.mLteRsrpThresholds));
     }
 
     /**
@@ -1070,7 +1100,8 @@
                 + " " + mTdScdmaRscp
                 + " " + (isGsm ? "gsm|lte" : "cdma")
                 + " " + (mUseOnlyRsrpForLteLevel ? "use_only_rsrp_for_lte_level" :
-                         "use_rsrp_and_rssnr_for_lte_level"));
+                         "use_rsrp_and_rssnr_for_lte_level")
+                + " " + (Arrays.toString(mLteRsrpThresholds)));
     }
 
     /** Returns the signal strength related to GSM. */
@@ -1126,6 +1157,10 @@
         mTdScdmaRscp = m.getInt("TdScdma");
         isGsm = m.getBoolean("isGsm");
         mUseOnlyRsrpForLteLevel = m.getBoolean("useOnlyRsrpForLteLevel");
+        ArrayList<Integer> lteRsrpThresholds = m.getIntegerArrayList("lteRsrpThresholds");
+        for (int i = 0; i < lteRsrpThresholds.size(); i++) {
+            mLteRsrpThresholds[i] = lteRsrpThresholds.get(i);
+        }
     }
 
     /**
@@ -1151,6 +1186,21 @@
         m.putInt("TdScdma", mTdScdmaRscp);
         m.putBoolean("isGsm", isGsm);
         m.putBoolean("useOnlyRsrpForLteLevel", mUseOnlyRsrpForLteLevel);
+        ArrayList<Integer> lteRsrpThresholds = new ArrayList<Integer>();
+        for (int value : mLteRsrpThresholds) {
+            lteRsrpThresholds.add(value);
+        }
+        m.putIntegerArrayList("lteRsrpThresholds", lteRsrpThresholds);
+    }
+
+    /**
+     * Gets the default threshold array for determining the display level of LTE signal bar.
+     *
+     * @return int array for determining the display level.
+     */
+    private int[] getDefaultLteRsrpThresholds() {
+        return CarrierConfigManager.getDefaultConfig().getIntArray(
+                CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY);
     }
 
     /**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2396a9e..2fafdf5 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -18,10 +18,12 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.app.BroadcastOptions;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -36,6 +38,7 @@
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.util.DisplayMetrics;
+import android.util.Log;
 
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.ISub;
@@ -46,6 +49,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * SubscriptionManager is the application interface to SubscriptionController
@@ -455,6 +459,39 @@
             = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
 
     /**
+     * Broadcast Action: Request a refresh of the billing relationship plans
+     * between a carrier and a specific subscriber.
+     * <p>
+     * Carrier apps are encouraged to implement this receiver, and the OS will
+     * provide an affordance to request a refresh. This affordance will only be
+     * shown when the carrier app is actively providing subscription plan
+     * information via {@link #setSubscriptionPlans(int, List)}.
+     * <p>
+     * Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to indicate which subscription
+     * the user is interested in.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @SystemApi
+    public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS
+            = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+
+    /**
+     * Broadcast Action: The billing relationship plans between a carrier and a
+     * specific subscriber has changed.
+     * <p>
+     * Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to indicate which subscription
+     * changed.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS)
+    public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED
+            = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED";
+
+    /**
      * Integer extra used with {@link #ACTION_DEFAULT_SUBSCRIPTION_CHANGED} and
      * {@link #ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED} to indicate the subscription
      * which has changed.
@@ -1637,7 +1674,7 @@
      * This method is only accessible to the following narrow set of apps:
      * <ul>
      * <li>The carrier app for this subscriberId, as determined by
-     * {@link TelephonyManager#hasCarrierPrivileges(int)}.
+     * {@link TelephonyManager#hasCarrierPrivileges()}.
      * <li>The carrier app explicitly delegated access through
      * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
      * </ul>
@@ -1664,7 +1701,7 @@
      * This method is only accessible to the following narrow set of apps:
      * <ul>
      * <li>The carrier app for this subscriberId, as determined by
-     * {@link TelephonyManager#hasCarrierPrivileges(int)}.
+     * {@link TelephonyManager#hasCarrierPrivileges()}.
      * <li>The carrier app explicitly delegated access through
      * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
      * </ul>
@@ -1695,8 +1732,8 @@
     }
 
     /**
-     * Create an {@link Intent} that will launch towards the carrier app that is
-     * currently defining the billing relationship plan through
+     * Create an {@link Intent} that can be launched towards the carrier app
+     * that is currently defining the billing relationship plan through
      * {@link #setSubscriptionPlans(int, List)}.
      *
      * @return ready to launch Intent targeted towards the carrier app, or
@@ -1725,4 +1762,55 @@
 
         return intent;
     }
+
+    /** @hide */
+    private @Nullable Intent createRefreshSubscriptionIntent(int subId) {
+        // Bail if no owner
+        final String owner = getSubscriptionPlansOwner(subId);
+        if (owner == null) return null;
+
+        // Bail if no plans
+        final List<SubscriptionPlan> plans = getSubscriptionPlans(subId);
+        if (plans.isEmpty()) return null;
+
+        final Intent intent = new Intent(ACTION_REFRESH_SUBSCRIPTION_PLANS);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.setPackage(owner);
+        intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId);
+
+        // Bail if not implemented
+        if (mContext.getPackageManager().queryBroadcastReceivers(intent, 0).isEmpty()) {
+            return null;
+        }
+
+        return intent;
+    }
+
+    /**
+     * Check if there is a carrier app that is currently defining the billing
+     * relationship plan through {@link #setSubscriptionPlans(int, List)} that
+     * supports refreshing of subscription plans.
+     *
+     * @hide
+     */
+    public boolean isSubscriptionPlansRefreshSupported(int subId) {
+        return createRefreshSubscriptionIntent(subId) != null;
+    }
+
+    /**
+     * Request that the carrier app that is currently defining the billing
+     * relationship plan through {@link #setSubscriptionPlans(int, List)}
+     * refresh its subscription plans.
+     * <p>
+     * If the app is able to successfully update the plans, you'll expect to
+     * receive the {@link #ACTION_SUBSCRIPTION_PLANS_CHANGED} broadcast.
+     *
+     * @hide
+     */
+    public void requestSubscriptionPlansRefresh(int subId) {
+        final Intent intent = createRefreshSubscriptionIntent(subId);
+        final BroadcastOptions options = BroadcastOptions.makeBasic();
+        options.setTemporaryAppWhitelistDuration(TimeUnit.MINUTES.toMillis(1));
+        mContext.sendBroadcast(intent, null, options.toBundle());
+    }
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index af5b190..8edc8b1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -53,6 +53,7 @@
 
 import com.android.ims.internal.IImsMMTelFeature;
 import com.android.ims.internal.IImsRcsFeature;
+import com.android.ims.internal.IImsRegistration;
 import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.ITelecomService;
@@ -831,6 +832,17 @@
             "android.telephony.event.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE";
 
     /**
+     * {@link android.telecom.Connection} event used to indicate that an IMS call has be
+     * successfully handed over from LTE to WIFI.
+     * <p>
+     * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}.
+     * The {@link Bundle} parameter is expected to be null when this connection event is used.
+     * @hide
+     */
+    public static final String EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI =
+            "android.telephony.event.EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI";
+
+    /**
      * {@link android.telecom.Connection} event used to indicate that an IMS call failed to be
      * handed over from LTE to WIFI.
      * <p>
@@ -2503,6 +2515,33 @@
         }
     }
 
+    /**
+     * Resets the Carrier Keys in the database. This involves 2 steps:
+     *  1. Delete the keys from the database.
+     *  2. Send an intent to download new Certificates.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * @hide
+     */
+    public void resetCarrierKeysForImsiEncryption() {
+        try {
+            IPhoneSubInfo info = getSubscriberInfo();
+            if (info == null) {
+                throw new RuntimeException("IMSI error: Subscriber Info is null");
+            }
+            int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
+            info.resetCarrierKeysForImsiEncryption(subId, mContext.getOpPackageName());
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
+            throw new RuntimeException("IMSI error: Remote Exception");
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
+            throw new RuntimeException("IMSI error: Null Pointer exception");
+        }
+    }
+
    /**
      * @param keyAvailability bitmask that defines the availabilty of keys for a type.
      * @param keyType the key type which is being checked. (WLAN, EPDG)
@@ -2538,7 +2577,7 @@
      * device keystore.
      * <p>
      * Requires Permission:
-     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      * @param imsiEncryptionInfo which includes the Key Type, the Public Key
      *        (java.security.PublicKey) and the Key Identifier.and the Key Identifier.
      *        The keyIdentifier Attribute value pair that helps a server locate
@@ -4921,6 +4960,25 @@
     }
 
     /**
+     * @return the {@IImsRegistration} interface that corresponds with the slot index and feature.
+     * @param slotIndex The SIM slot corresponding to the ImsService ImsRegistration is active for.
+     * @param feature An integer indicating the feature that we wish to get the ImsRegistration for.
+     * Corresponds to features defined in ImsFeature.
+     * @hide
+     */
+    public @Nullable IImsRegistration getImsRegistration(int slotIndex, int feature) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getImsRegistration(slotIndex, feature);
+            }
+        } catch (RemoteException e) {
+            Rlog.e(TAG, "getImsRegistration, RemoteException: " + e.getMessage());
+        }
+        return null;
+    }
+
+    /**
      * Set IMS registration state
      *
      * @param Registration state
@@ -6253,8 +6311,10 @@
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      *
-     * @hide
+     * {@hide}
      **/
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setSimPowerState(int state) {
         setSimPowerStateForSlot(getSlotIndex(), state);
     }
@@ -6273,8 +6333,10 @@
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      *
-     * @hide
+     * {@hide}
      **/
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setSimPowerStateForSlot(int slotIndex, int state) {
         try {
             ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
index 8ed96a3..7eeb1ce 100644
--- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
@@ -15,12 +15,10 @@
  */
 package android.telephony;
 
-import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
-
-import android.telecom.PhoneAccountHandle;
 import android.telephony.VisualVoicemailService.VisualVoicemailTask;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -75,6 +73,7 @@
         private String mClientPrefix = DEFAULT_CLIENT_PREFIX;
         private List<String> mOriginatingNumbers = DEFAULT_ORIGINATING_NUMBERS;
         private int mDestinationPort = DEFAULT_DESTINATION_PORT;
+        private String mPackageName;
 
         public VisualVoicemailSmsFilterSettings build() {
             return new VisualVoicemailSmsFilterSettings(this);
@@ -116,6 +115,15 @@
             return this;
         }
 
+        /**
+         * The package that registered this filter.
+         *
+         * @hide
+         */
+        public Builder setPackageName(String packageName) {
+            mPackageName = packageName;
+            return this;
+        }
     }
 
     /**
@@ -138,12 +146,20 @@
     public final int destinationPort;
 
     /**
+     * The package that registered this filter.
+     *
+     * @hide
+     */
+    public final String packageName;
+
+    /**
      * Use {@link Builder} to construct
      */
     private VisualVoicemailSmsFilterSettings(Builder builder) {
         clientPrefix = builder.mClientPrefix;
         originatingNumbers = builder.mOriginatingNumbers;
         destinationPort = builder.mDestinationPort;
+        packageName = builder.mPackageName;
     }
 
     public static final Creator<VisualVoicemailSmsFilterSettings> CREATOR =
@@ -154,7 +170,7 @@
                     builder.setClientPrefix(in.readString());
                     builder.setOriginatingNumbers(in.createStringArrayList());
                     builder.setDestinationPort(in.readInt());
-
+                    builder.setPackageName(in.readString());
                     return builder.build();
                 }
 
@@ -174,10 +190,11 @@
         dest.writeString(clientPrefix);
         dest.writeStringList(originatingNumbers);
         dest.writeInt(destinationPort);
+        dest.writeString(packageName);
     }
 
     @Override
-    public String toString(){
+    public String toString() {
         return "[VisualVoicemailSmsFilterSettings "
                 + "clientPrefix=" + clientPrefix
                 + ", originatingNumbers=" + originatingNumbers
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/telephony/java/android/telephony/data/ApnSetting.aidl
similarity index 86%
copy from telephony/java/android/telephony/data/InterfaceAddress.aidl
copy to telephony/java/android/telephony/data/ApnSetting.aidl
index d750363..381e5e8 100644
--- a/telephony/java/android/telephony/data/InterfaceAddress.aidl
+++ b/telephony/java/android/telephony/data/ApnSetting.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -13,8 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-/** @hide */
 package android.telephony.data;
 
-parcelable InterfaceAddress;
+parcelable ApnSetting;
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
new file mode 100644
index 0000000..2ab8d4f
--- /dev/null
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -0,0 +1,1370 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.data;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.hardware.radio.V1_0.ApnTypes;
+import android.net.NetworkUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.Telephony;
+import android.telephony.Rlog;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.net.URL;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A class representing an APN configuration.
+ */
+public class ApnSetting implements Parcelable {
+
+    static final String LOG_TAG = "ApnSetting";
+    private static final boolean VDBG = false;
+
+    private final String mEntryName;
+    private final String mApnName;
+    private final InetAddress mProxy;
+    private final int mPort;
+    private final URL mMmsc;
+    private final InetAddress mMmsProxy;
+    private final int mMmsPort;
+    private final String mUser;
+    private final String mPassword;
+    private final int mAuthType;
+    private final List<String> mTypes;
+    private final int mTypesBitmap;
+    private final int mId;
+    private final String mOperatorNumeric;
+    private final String mProtocol;
+    private final String mRoamingProtocol;
+    private final int mMtu;
+
+    private final boolean mCarrierEnabled;
+    private final int mBearer;
+    private final int mBearerBitmask;
+
+    private final int mProfileId;
+
+    private final boolean mModemCognitive;
+    private final int mMaxConns;
+    private final int mWaitTime;
+    private final int mMaxConnsTime;
+
+    private final String mMvnoType;
+    private final String mMvnoMatchData;
+
+    private boolean mPermanentFailed = false;
+
+    /**
+     * Returns the types bitmap of the APN.
+     *
+     * @return types bitmap of the APN
+     * @hide
+     */
+    public int getTypesBitmap() {
+        return mTypesBitmap;
+    }
+
+    /**
+     * Returns the MTU size of the mobile interface to which the APN connected.
+     *
+     * @return the MTU size of the APN
+     * @hide
+     */
+    public int getMtu() {
+        return mMtu;
+    }
+
+    /**
+     * Radio Access Technology info.
+     * To check what values can hold, refer to ServiceState.java.
+     * This should be spread to other technologies,
+     * but currently only used for LTE(14) and EHRPD(13).
+     *
+     * @return the bearer info of the APN
+     * @hide
+     */
+    public int getBearer() {
+        return mBearer;
+    }
+
+    /**
+     * Returns the radio access technology bitmask for this APN.
+     *
+     * To check what values can hold, refer to ServiceState.java. This is a bitmask of radio
+     * technologies in ServiceState.
+     * This should be spread to other technologies,
+     * but currently only used for LTE(14) and EHRPD(13).
+     *
+     * @return the radio access technology bitmask
+     * @hide
+     */
+    public int getBearerBitmask() {
+        return mBearerBitmask;
+    }
+
+    /**
+     * Returns the profile id to which the APN saved in modem.
+     *
+     * @return the profile id of the APN
+     * @hide
+     */
+    public int getProfileId() {
+        return mProfileId;
+    }
+
+    /**
+     * Returns if the APN setting is to be set in modem.
+     *
+     * @return is the APN setting to be set in modem
+     * @hide
+     */
+    public boolean getModemCognitive() {
+        return mModemCognitive;
+    }
+
+    /**
+     * Returns the max connections of this APN.
+     *
+     * @return the max connections of this APN
+     * @hide
+     */
+    public int getMaxConns() {
+        return mMaxConns;
+    }
+
+    /**
+     * Returns the wait time for retry of the APN.
+     *
+     * @return the wait time for retry of the APN
+     * @hide
+     */
+    public int getWaitTime() {
+        return mWaitTime;
+    }
+
+    /**
+     * Returns the time to limit max connection for the APN.
+     *
+     * @return the time to limit max connection for the APN
+     * @hide
+     */
+    public int getMaxConnsTime() {
+        return mMaxConnsTime;
+    }
+
+    /**
+     * Returns the MVNO data. Examples:
+     *   "spn": A MOBILE, BEN NL
+     *   "imsi": 302720x94, 2060188
+     *   "gid": 4E, 33
+     *   "iccid": 898603 etc..
+     *
+     * @return the mvno match data
+     * @hide
+     */
+    public String getMvnoMatchData() {
+        return mMvnoMatchData;
+    }
+
+    /**
+     * Indicates this APN setting is permanently failed and cannot be
+     * retried by the retry manager anymore.
+     *
+     * @return if this APN setting is permanently failed
+     * @hide
+     */
+    public boolean getPermanentFailed() {
+        return mPermanentFailed;
+    }
+
+    /**
+     * Sets if this APN setting is permanently failed.
+     *
+     * @param permanentFailed if this APN setting is permanently failed
+     * @hide
+     */
+    public void setPermanentFailed(boolean permanentFailed) {
+        mPermanentFailed = permanentFailed;
+    }
+
+    /**
+     * Returns the entry name of the APN.
+     *
+     * @return the entry name for the APN
+     */
+    public String getEntryName() {
+        return mEntryName;
+    }
+
+    /**
+     * Returns the name of the APN.
+     *
+     * @return APN name
+     */
+    public String getApnName() {
+        return mApnName;
+    }
+
+    /**
+     * Returns the proxy address of the APN.
+     *
+     * @return proxy address.
+     */
+    public InetAddress getProxy() {
+        return mProxy;
+    }
+
+    /**
+     * Returns the proxy port of the APN.
+     *
+     * @return proxy port
+     */
+    public int getPort() {
+        return mPort;
+    }
+    /**
+     * Returns the MMSC URL of the APN.
+     *
+     * @return MMSC URL.
+     */
+    public URL getMmsc() {
+        return mMmsc;
+    }
+
+    /**
+     * Returns the MMS proxy address of the APN.
+     *
+     * @return MMS proxy address.
+     */
+    public InetAddress getMmsProxy() {
+        return mMmsProxy;
+    }
+
+    /**
+     * Returns the MMS proxy port of the APN.
+     *
+     * @return MMS proxy port
+     */
+    public int getMmsPort() {
+        return mMmsPort;
+    }
+
+    /**
+     * Returns the APN username of the APN.
+     *
+     * @return APN username
+     */
+    public String getUser() {
+        return mUser;
+    }
+
+    /**
+     * Returns the APN password of the APN.
+     *
+     * @return APN password
+     */
+    public String getPassword() {
+        return mPassword;
+    }
+
+    /** @hide */
+    @IntDef({
+            AUTH_TYPE_NONE,
+            AUTH_TYPE_PAP,
+            AUTH_TYPE_CHAP,
+            AUTH_TYPE_PAP_OR_CHAP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AuthType {}
+
+    /**
+     * Returns the authentication type of the APN.
+     *
+     * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}.
+     *
+     * @return authentication type
+     */
+    @AuthType
+    public int getAuthType() {
+        return mAuthType;
+    }
+
+    /** @hide */
+    @StringDef({
+            TYPE_DEFAULT,
+            TYPE_MMS,
+            TYPE_SUPL,
+            TYPE_DUN,
+            TYPE_HIPRI,
+            TYPE_FOTA,
+            TYPE_IMS,
+            TYPE_CBS,
+            TYPE_IA,
+            TYPE_EMERGENCY
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ApnType {}
+
+    /**
+     * Returns the list of APN types of the APN.
+     *
+     * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}.
+     *
+     * @return the list of APN types
+     */
+    @ApnType
+    public List<String> getTypes() {
+        return mTypes;
+    }
+
+    /**
+     * Returns the unique database id for this entry.
+     *
+     * @return the unique database id
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the numeric operator ID for the APN. Usually
+     * {@link android.provider.Telephony.Carriers#MCC} +
+     * {@link android.provider.Telephony.Carriers#MNC}.
+     *
+     * @return the numeric operator ID
+     */
+    public String getOperatorNumeric() {
+        return mOperatorNumeric;
+    }
+
+    /** @hide */
+    @StringDef({
+            PROTOCOL_IP,
+            PROTOCOL_IPV6,
+            PROTOCOL_IPV4V6,
+            PROTOCOL_PPP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProtocolType {}
+
+    /**
+     * Returns the protocol to use to connect to this APN.
+     *
+     * One of the {@code PDP_type} values in TS 27.007 section 10.1.1.
+     * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}.
+     *
+     * @return the protocol
+     */
+    @ProtocolType
+    public String getProtocol() {
+        return mProtocol;
+    }
+
+    /**
+     * Returns the protocol to use to connect to this APN when roaming.
+     *
+     * The syntax is the same as {@link android.provider.Telephony.Carriers#PROTOCOL}.
+     *
+     * @return the roaming protocol
+     */
+    public String getRoamingProtocol() {
+        return mRoamingProtocol;
+    }
+
+    /**
+     * Returns the current status of APN.
+     *
+     * {@code true} : enabled APN.
+     * {@code false} : disabled APN.
+     *
+     * @return the current status
+     */
+    public boolean isEnabled() {
+        return mCarrierEnabled;
+    }
+
+    /** @hide */
+    @StringDef({
+            MVNO_TYPE_SPN,
+            MVNO_TYPE_IMSI,
+            MVNO_TYPE_GID,
+            MVNO_TYPE_ICCID,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MvnoType {}
+
+    /**
+     * Returns the MVNO match type for this APN.
+     *
+     * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}.
+     *
+     * @return the MVNO match type
+     */
+    @MvnoType
+    public String getMvnoType() {
+        return mMvnoType;
+    }
+
+    private ApnSetting(Builder builder) {
+        this.mEntryName = builder.mEntryName;
+        this.mApnName = builder.mApnName;
+        this.mProxy = builder.mProxy;
+        this.mPort = builder.mPort;
+        this.mMmsc = builder.mMmsc;
+        this.mMmsProxy = builder.mMmsProxy;
+        this.mMmsPort = builder.mMmsPort;
+        this.mUser = builder.mUser;
+        this.mPassword = builder.mPassword;
+        this.mAuthType = builder.mAuthType;
+        this.mTypes = (builder.mTypes == null ? new ArrayList<String>() : builder.mTypes);
+        this.mTypesBitmap = builder.mTypesBitmap;
+        this.mId = builder.mId;
+        this.mOperatorNumeric = builder.mOperatorNumeric;
+        this.mProtocol = builder.mProtocol;
+        this.mRoamingProtocol = builder.mRoamingProtocol;
+        this.mMtu = builder.mMtu;
+        this.mCarrierEnabled = builder.mCarrierEnabled;
+        this.mBearer = builder.mBearer;
+        this.mBearerBitmask = builder.mBearerBitmask;
+        this.mProfileId = builder.mProfileId;
+        this.mModemCognitive = builder.mModemCognitive;
+        this.mMaxConns = builder.mMaxConns;
+        this.mWaitTime = builder.mWaitTime;
+        this.mMaxConnsTime = builder.mMaxConnsTime;
+        this.mMvnoType = builder.mMvnoType;
+        this.mMvnoMatchData = builder.mMvnoMatchData;
+    }
+
+    /** @hide */
+    public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
+            String apnName, InetAddress proxy, int port, URL mmsc, InetAddress mmsProxy,
+            int mmsPort, String user, String password, int authType, List<String> types,
+            String protocol, String roamingProtocol, boolean carrierEnabled, int bearer,
+            int bearerBitmask, int profileId, boolean modemCognitive, int maxConns,
+            int waitTime, int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) {
+        return new Builder()
+                .setId(id)
+                .setOperatorNumeric(operatorNumeric)
+                .setEntryName(entryName)
+                .setApnName(apnName)
+                .setProxy(proxy)
+                .setPort(port)
+                .setMmsc(mmsc)
+                .setMmsProxy(mmsProxy)
+                .setMmsPort(mmsPort)
+                .setUser(user)
+                .setPassword(password)
+                .setAuthType(authType)
+                .setTypes(types)
+                .setProtocol(protocol)
+                .setRoamingProtocol(roamingProtocol)
+                .setCarrierEnabled(carrierEnabled)
+                .setBearer(bearer)
+                .setBearerBitmask(bearerBitmask)
+                .setProfileId(profileId)
+                .setModemCognitive(modemCognitive)
+                .setMaxConns(maxConns)
+                .setWaitTime(waitTime)
+                .setMaxConnsTime(maxConnsTime)
+                .setMtu(mtu)
+                .setMvnoType(mvnoType)
+                .setMvnoMatchData(mvnoMatchData)
+                .build();
+    }
+
+    /** @hide */
+    public static ApnSetting makeApnSetting(Cursor cursor) {
+        String[] types = parseTypes(
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
+
+        return makeApnSetting(
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
+                inetAddressFromString(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
+                portFromString(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
+                URLFromString(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
+                inetAddressFromString(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
+                portFromString(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
+                Arrays.asList(types),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
+                cursor.getString(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.ROAMING_PROTOCOL)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.CARRIER_ENABLED)) == 1,
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.BEARER_BITMASK)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.MODEM_COGNITIVE)) == 1,
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.MAX_CONNS_TIME)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
+                cursor.getString(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.MVNO_TYPE)),
+                cursor.getString(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.MVNO_MATCH_DATA)));
+    }
+
+    /** @hide */
+    public static ApnSetting makeApnSetting(ApnSetting apn) {
+        return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName,
+                apn.mProxy, apn.mPort, apn.mMmsc, apn.mMmsProxy, apn.mMmsPort, apn.mUser,
+                apn.mPassword, apn.mAuthType, apn.mTypes, apn.mProtocol, apn.mRoamingProtocol,
+                apn.mCarrierEnabled, apn.mBearer, apn.mBearerBitmask, apn.mProfileId,
+                apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, apn.mMaxConnsTime, apn.mMtu,
+                apn.mMvnoType, apn.mMvnoMatchData);
+    }
+
+    /** @hide */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[ApnSettingV3] ")
+                .append(mEntryName)
+                .append(", ").append(mId)
+                .append(", ").append(mOperatorNumeric)
+                .append(", ").append(mApnName)
+                .append(", ").append(inetAddressToString(mProxy))
+                .append(", ").append(URLToString(mMmsc))
+                .append(", ").append(inetAddressToString(mMmsProxy))
+                .append(", ").append(portToString(mMmsPort))
+                .append(", ").append(portToString(mPort))
+                .append(", ").append(mAuthType).append(", ");
+        for (int i = 0; i < mTypes.size(); i++) {
+            sb.append(mTypes.get(i));
+            if (i < mTypes.size() - 1) {
+                sb.append(" | ");
+            }
+        }
+        sb.append(", ").append(mProtocol);
+        sb.append(", ").append(mRoamingProtocol);
+        sb.append(", ").append(mCarrierEnabled);
+        sb.append(", ").append(mBearer);
+        sb.append(", ").append(mBearerBitmask);
+        sb.append(", ").append(mProfileId);
+        sb.append(", ").append(mModemCognitive);
+        sb.append(", ").append(mMaxConns);
+        sb.append(", ").append(mWaitTime);
+        sb.append(", ").append(mMaxConnsTime);
+        sb.append(", ").append(mMtu);
+        sb.append(", ").append(mMvnoType);
+        sb.append(", ").append(mMvnoMatchData);
+        sb.append(", ").append(mPermanentFailed);
+        return sb.toString();
+    }
+
+    /**
+     * Returns true if there are MVNO params specified.
+     * @hide
+     */
+    public boolean hasMvnoParams() {
+        return !TextUtils.isEmpty(mMvnoType) && !TextUtils.isEmpty(mMvnoMatchData);
+    }
+
+    /** @hide */
+    public boolean canHandleType(String type) {
+        if (!mCarrierEnabled) return false;
+        boolean wildcardable = true;
+        if (TYPE_IA.equalsIgnoreCase(type)) wildcardable = false;
+        for (String t : mTypes) {
+            // DEFAULT handles all, and HIPRI is handled by DEFAULT
+            if (t.equalsIgnoreCase(type)
+                    || (wildcardable && t.equalsIgnoreCase(TYPE_ALL))
+                    || (t.equalsIgnoreCase(TYPE_DEFAULT)
+                    && type.equalsIgnoreCase(TYPE_HIPRI))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // check whether the types of two APN same (even only one type of each APN is same)
+    private boolean typeSameAny(ApnSetting first, ApnSetting second) {
+        if (VDBG) {
+            StringBuilder apnType1 = new StringBuilder(first.mApnName + ": ");
+            for (int index1 = 0; index1 < first.mTypes.size(); index1++) {
+                apnType1.append(first.mTypes.get(index1));
+                apnType1.append(",");
+            }
+
+            StringBuilder apnType2 = new StringBuilder(second.mApnName + ": ");
+            for (int index1 = 0; index1 < second.mTypes.size(); index1++) {
+                apnType2.append(second.mTypes.get(index1));
+                apnType2.append(",");
+            }
+            Rlog.d(LOG_TAG, "APN1: is " + apnType1);
+            Rlog.d(LOG_TAG, "APN2: is " + apnType2);
+        }
+
+        for (int index1 = 0; index1 < first.mTypes.size(); index1++) {
+            for (int index2 = 0; index2 < second.mTypes.size(); index2++) {
+                if (first.mTypes.get(index1).equals(ApnSetting.TYPE_ALL)
+                        || second.mTypes.get(index2).equals(ApnSetting.TYPE_ALL)
+                        || first.mTypes.get(index1).equals(second.mTypes.get(index2))) {
+                    if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return true");
+                    return true;
+                }
+            }
+        }
+
+        if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false");
+        return false;
+    }
+
+    // TODO - if we have this function we should also have hashCode.
+    // Also should handle changes in type order and perhaps case-insensitivity
+    /** @hide */
+    public boolean equals(Object o) {
+        if (o instanceof ApnSetting == false) {
+            return false;
+        }
+
+        ApnSetting other = (ApnSetting) o;
+
+        return mEntryName.equals(other.mEntryName)
+                && Objects.equals(mId, other.mId)
+                && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+                && Objects.equals(mApnName, other.mApnName)
+                && Objects.equals(mProxy, other.mProxy)
+                && Objects.equals(mMmsc, other.mMmsc)
+                && Objects.equals(mMmsProxy, other.mMmsProxy)
+                && Objects.equals(mMmsPort, other.mMmsPort)
+                && Objects.equals(mPort,other.mPort)
+                && Objects.equals(mUser, other.mUser)
+                && Objects.equals(mPassword, other.mPassword)
+                && Objects.equals(mAuthType, other.mAuthType)
+                && Objects.equals(mTypes, other.mTypes)
+                && Objects.equals(mTypesBitmap, other.mTypesBitmap)
+                && Objects.equals(mProtocol, other.mProtocol)
+                && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
+                && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+                && Objects.equals(mBearer, other.mBearer)
+                && Objects.equals(mBearerBitmask, other.mBearerBitmask)
+                && Objects.equals(mProfileId, other.mProfileId)
+                && Objects.equals(mModemCognitive, other.mModemCognitive)
+                && Objects.equals(mMaxConns, other.mMaxConns)
+                && Objects.equals(mWaitTime, other.mWaitTime)
+                && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+                && Objects.equals(mMtu, other.mMtu)
+                && Objects.equals(mMvnoType, other.mMvnoType)
+                && Objects.equals(mMvnoMatchData, other.mMvnoMatchData);
+    }
+
+    /**
+     * Compare two APN settings
+     *
+     * Note: This method does not compare 'id', 'bearer', 'bearerBitmask'. We only use this for
+     * determining if tearing a data call is needed when conditions change. See
+     * cleanUpConnectionsOnUpdatedApns in DcTracker.
+     *
+     * @param o the other object to compare
+     * @param isDataRoaming True if the device is on data roaming
+     * @return True if the two APN settings are same
+     * @hide
+     */
+    public boolean equals(Object o, boolean isDataRoaming) {
+        if (!(o instanceof ApnSetting)) {
+            return false;
+        }
+
+        ApnSetting other = (ApnSetting) o;
+
+        return mEntryName.equals(other.mEntryName)
+                && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+                && Objects.equals(mApnName, other.mApnName)
+                && Objects.equals(mProxy, other.mProxy)
+                && Objects.equals(mMmsc, other.mMmsc)
+                && Objects.equals(mMmsProxy, other.mMmsProxy)
+                && Objects.equals(mMmsPort, other.mMmsPort)
+                && Objects.equals(mPort, other.mPort)
+                && Objects.equals(mUser, other.mUser)
+                && Objects.equals(mPassword, other.mPassword)
+                && Objects.equals(mAuthType, other.mAuthType)
+                && Objects.equals(mTypes, other.mTypes)
+                && Objects.equals(mTypesBitmap, other.mTypesBitmap)
+                && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol))
+                && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
+                && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+                && Objects.equals(mProfileId, other.mProfileId)
+                && Objects.equals(mModemCognitive, other.mModemCognitive)
+                && Objects.equals(mMaxConns, other.mMaxConns)
+                && Objects.equals(mWaitTime, other.mWaitTime)
+                && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+                && Objects.equals(mMtu, other.mMtu)
+                && Objects.equals(mMvnoType, other.mMvnoType)
+                && Objects.equals(mMvnoMatchData, other.mMvnoMatchData);
+    }
+
+    /**
+     * Check if neither mention DUN and are substantially similar
+     *
+     * @param other The other APN settings to compare
+     * @return True if two APN settings are similar
+     * @hide
+     */
+    public boolean similar(ApnSetting other) {
+        return (!this.canHandleType(TYPE_DUN)
+                && !other.canHandleType(TYPE_DUN)
+                && Objects.equals(this.mApnName, other.mApnName)
+                && !typeSameAny(this, other)
+                && xorEqualsInetAddress(this.mProxy, other.mProxy)
+                && xorEqualsPort(this.mPort, other.mPort)
+                && xorEquals(this.mProtocol, other.mProtocol)
+                && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
+                && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
+                && Objects.equals(this.mBearerBitmask, other.mBearerBitmask)
+                && Objects.equals(this.mProfileId, other.mProfileId)
+                && Objects.equals(this.mMvnoType, other.mMvnoType)
+                && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
+                && xorEqualsURL(this.mMmsc, other.mMmsc)
+                && xorEqualsInetAddress(this.mMmsProxy, other.mMmsProxy)
+                && xorEqualsPort(this.mMmsPort, other.mMmsPort));
+    }
+
+    // Equal or one is not specified.
+    private boolean xorEquals(String first, String second) {
+        return (Objects.equals(first, second)
+                || TextUtils.isEmpty(first)
+                || TextUtils.isEmpty(second));
+    }
+
+    // Equal or one is not specified.
+    private boolean xorEqualsInetAddress(InetAddress first, InetAddress second) {
+        return first == null || second == null || first.equals(second);
+    }
+
+    // Equal or one is not specified.
+    private boolean xorEqualsURL(URL first, URL second) {
+        return first == null || second == null || first.equals(second);
+    }
+
+    // Equal or one is not specified.
+    private boolean xorEqualsPort(int first, int second) {
+        return first == -1 || second == -1 || Objects.equals(first, second);
+    }
+
+    // Helper function to convert APN string into a 32-bit bitmask.
+    private static int getApnBitmask(String apn) {
+        switch (apn) {
+            case TYPE_DEFAULT: return ApnTypes.DEFAULT;
+            case TYPE_MMS: return ApnTypes.MMS;
+            case TYPE_SUPL: return ApnTypes.SUPL;
+            case TYPE_DUN: return ApnTypes.DUN;
+            case TYPE_HIPRI: return ApnTypes.HIPRI;
+            case TYPE_FOTA: return ApnTypes.FOTA;
+            case TYPE_IMS: return ApnTypes.IMS;
+            case TYPE_CBS: return ApnTypes.CBS;
+            case TYPE_IA: return ApnTypes.IA;
+            case TYPE_EMERGENCY: return ApnTypes.EMERGENCY;
+            case TYPE_ALL: return ApnTypes.ALL;
+            default: return ApnTypes.NONE;
+        }
+    }
+
+    private String deParseTypes(List<String> types) {
+        if (types == null) {
+            return null;
+        }
+        return TextUtils.join(",", types);
+    }
+
+    /** @hide */
+    // Called by DPM.
+    public ContentValues toContentValues() {
+        ContentValues apnValue = new ContentValues();
+        if (mOperatorNumeric != null) {
+            apnValue.put(Telephony.Carriers.NUMERIC, mOperatorNumeric);
+        }
+        if (mEntryName != null) {
+            apnValue.put(Telephony.Carriers.NAME, mEntryName);
+        }
+        if (mApnName != null) {
+            apnValue.put(Telephony.Carriers.APN, mApnName);
+        }
+        if (mProxy != null) {
+            apnValue.put(Telephony.Carriers.PROXY, inetAddressToString(mProxy));
+        }
+        apnValue.put(Telephony.Carriers.PORT, portToString(mPort));
+        if (mMmsc != null) {
+            apnValue.put(Telephony.Carriers.MMSC, URLToString(mMmsc));
+        }
+        apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsPort));
+        if (mMmsProxy != null) {
+            apnValue.put(Telephony.Carriers.MMSPROXY, inetAddressToString(mMmsProxy));
+        }
+        if (mUser != null) {
+            apnValue.put(Telephony.Carriers.USER, mUser);
+        }
+        if (mPassword != null) {
+            apnValue.put(Telephony.Carriers.PASSWORD, mPassword);
+        }
+        apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType);
+        String apnType = deParseTypes(mTypes);
+        if (apnType != null) {
+            apnValue.put(Telephony.Carriers.TYPE, apnType);
+        }
+        if (mProtocol != null) {
+            apnValue.put(Telephony.Carriers.PROTOCOL, mProtocol);
+        }
+        if (mRoamingProtocol != null) {
+            apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, mRoamingProtocol);
+        }
+        apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
+        // networkTypeBit.
+        apnValue.put(Telephony.Carriers.BEARER_BITMASK, mBearerBitmask);
+        if (mMvnoType != null) {
+            apnValue.put(Telephony.Carriers.MVNO_TYPE, mMvnoType);
+        }
+
+        return apnValue;
+    }
+
+    /**
+     * @param types comma delimited list of APN types
+     * @return array of APN types
+     * @hide
+     */
+    public static String[] parseTypes(String types) {
+        String[] result;
+        // If unset, set to DEFAULT.
+        if (TextUtils.isEmpty(types)) {
+            result = new String[1];
+            result[0] = TYPE_ALL;
+        } else {
+            result = types.split(",");
+        }
+        return result;
+    }
+
+    private static URL URLFromString(String url) {
+        try {
+            return TextUtils.isEmpty(url) ? null : new URL(url);
+        } catch (MalformedURLException e) {
+            Log.e(LOG_TAG, "Can't parse URL from string.");
+            return null;
+        }
+    }
+
+    private static String URLToString(URL url) {
+        return url == null ? "" : url.toString();
+    }
+
+    private static InetAddress inetAddressFromString(String inetAddress) {
+        if (TextUtils.isEmpty(inetAddress)) {
+            return null;
+        }
+        try {
+            return InetAddress.getByName(inetAddress);
+        } catch (UnknownHostException e) {
+            Log.e(LOG_TAG, "Can't parse InetAddress from string: unknown host.");
+            return null;
+        }
+    }
+
+    private static String inetAddressToString(InetAddress inetAddress) {
+        if (inetAddress == null) {
+            return null;
+        }
+        return TextUtils.isEmpty(inetAddress.getHostName())
+                ? inetAddress.getHostAddress() : inetAddress.getHostName();
+    }
+
+    private static int portFromString(String strPort) {
+        int port = -1;
+        if (!TextUtils.isEmpty(strPort)) {
+            try {
+                port = Integer.parseInt(strPort);
+            } catch (NumberFormatException e) {
+                Log.e(LOG_TAG, "Can't parse port from String");
+            }
+        }
+        return port;
+    }
+
+    private static String portToString(int port) {
+        return port == -1 ? "" : Integer.toString(port);
+    }
+
+    // Implement Parcelable.
+    @Override
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    /** @hide */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mId);
+        dest.writeString(mOperatorNumeric);
+        dest.writeString(mEntryName);
+        dest.writeString(mApnName);
+        dest.writeValue(mProxy);
+        dest.writeInt(mPort);
+        dest.writeValue(mMmsc);
+        dest.writeValue(mMmsProxy);
+        dest.writeInt(mMmsPort);
+        dest.writeString(mUser);
+        dest.writeString(mPassword);
+        dest.writeInt(mAuthType);
+        dest.writeStringArray(mTypes.toArray(new String[0]));
+        dest.writeString(mProtocol);
+        dest.writeString(mRoamingProtocol);
+        dest.writeInt(mCarrierEnabled ? 1: 0);
+        dest.writeString(mMvnoType);
+    }
+
+    private static ApnSetting readFromParcel(Parcel in) {
+        return makeApnSetting(in.readInt(), in.readString(), in.readString(), in.readString(),
+                (InetAddress)in.readValue(InetAddress.class.getClassLoader()),
+                in.readInt(), (URL)in.readValue(URL.class.getClassLoader()),
+                (InetAddress)in.readValue(InetAddress.class.getClassLoader()),
+                in.readInt(), in.readString(), in.readString(), in.readInt(),
+                Arrays.asList(in.readStringArray()), in.readString(), in.readString(),
+                in.readInt() > 0, 0, 0, 0, false, 0, 0, 0, 0, in.readString(), null);
+    }
+
+    public static final Parcelable.Creator<ApnSetting> CREATOR =
+            new Parcelable.Creator<ApnSetting>() {
+                @Override
+                public ApnSetting createFromParcel(Parcel in) {
+                    return readFromParcel(in);
+                }
+
+                @Override
+                public ApnSetting[] newArray(int size) {
+                    return new ApnSetting[size];
+                }
+            };
+
+    /**
+     * APN types for data connections.  These are usage categories for an APN
+     * entry.  One APN entry may support multiple APN types, eg, a single APN
+     * may service regular internet traffic ("default") as well as MMS-specific
+     * connections.<br/>
+     * ALL is a special type to indicate that this APN entry can
+     * service all data connections.
+     */
+    public static final String TYPE_ALL = "*";
+    /** APN type for default data traffic */
+    public static final String TYPE_DEFAULT = "default";
+    /** APN type for MMS traffic */
+    public static final String TYPE_MMS = "mms";
+    /** APN type for SUPL assisted GPS */
+    public static final String TYPE_SUPL = "supl";
+    /** APN type for DUN traffic */
+    public static final String TYPE_DUN = "dun";
+    /** APN type for HiPri traffic */
+    public static final String TYPE_HIPRI = "hipri";
+    /** APN type for FOTA */
+    public static final String TYPE_FOTA = "fota";
+    /** APN type for IMS */
+    public static final String TYPE_IMS = "ims";
+    /** APN type for CBS */
+    public static final String TYPE_CBS = "cbs";
+    /** APN type for IA Initial Attach APN */
+    public static final String TYPE_IA = "ia";
+    /** APN type for Emergency PDN. This is not an IA apn, but is used
+     * for access to carrier services in an emergency call situation. */
+    public static final String TYPE_EMERGENCY = "emergency";
+    /**
+     * Array of all APN types
+     *
+     * @hide
+     */
+    public static final String[] ALL_TYPES = {
+            TYPE_DEFAULT,
+            TYPE_MMS,
+            TYPE_SUPL,
+            TYPE_DUN,
+            TYPE_HIPRI,
+            TYPE_FOTA,
+            TYPE_IMS,
+            TYPE_CBS,
+            TYPE_IA,
+            TYPE_EMERGENCY
+    };
+
+    // Possible values for authentication types.
+    public static final int AUTH_TYPE_NONE = 0;
+    public static final int AUTH_TYPE_PAP = 1;
+    public static final int AUTH_TYPE_CHAP = 2;
+    public static final int AUTH_TYPE_PAP_OR_CHAP = 3;
+
+    // Possible values for protocol.
+    public static final String PROTOCOL_IP = "IP";
+    public static final String PROTOCOL_IPV6 = "IPV6";
+    public static final String PROTOCOL_IPV4V6 = "IPV4V6";
+    public static final String PROTOCOL_PPP = "PPP";
+
+    // Possible values for MVNO type.
+    public static final String MVNO_TYPE_SPN = "spn";
+    public static final String MVNO_TYPE_IMSI = "imsi";
+    public static final String MVNO_TYPE_GID = "gid";
+    public static final String MVNO_TYPE_ICCID = "iccid";
+
+    public static class Builder{
+        private String mEntryName;
+        private String mApnName;
+        private InetAddress mProxy;
+        private int mPort = -1;
+        private URL mMmsc;
+        private InetAddress mMmsProxy;
+        private int mMmsPort = -1;
+        private String mUser;
+        private String mPassword;
+        private int mAuthType;
+        private List<String> mTypes;
+        private int mTypesBitmap;
+        private int mId;
+        private String mOperatorNumeric;
+        private String mProtocol;
+        private String mRoamingProtocol;
+        private int mMtu;
+        private boolean mCarrierEnabled;
+        private int mBearer;
+        private int mBearerBitmask;
+        private int mProfileId;
+        private boolean mModemCognitive;
+        private int mMaxConns;
+        private int mWaitTime;
+        private int mMaxConnsTime;
+        private String mMvnoType;
+        private String mMvnoMatchData;
+
+        /**
+         * Default constructor for Builder.
+         */
+        public Builder() {}
+
+        /**
+         * Set the MTU size of the mobile interface to which the APN connected.
+         *
+         * @param mtu the MTU size to set for the APN
+         * @hide
+         */
+        public Builder setMtu(int mtu) {
+            this.mMtu = mtu;
+            return this;
+        }
+
+        /**
+         * Sets bearer info.
+         *
+         * @param bearer the bearer info to set for the APN
+         * @hide
+         */
+        public Builder setBearer(int bearer) {
+            this.mBearer = bearer;
+            return this;
+        }
+
+        /**
+         * Sets the radio access technology bitmask for this APN.
+         *
+         * @param bearerBitmask the radio access technology bitmask to set for this APN
+         * @hide
+         */
+        public Builder setBearerBitmask(int bearerBitmask) {
+            this.mBearerBitmask = bearerBitmask;
+            return this;
+        }
+
+        /**
+         * Sets the profile id to which the APN saved in modem.
+         *
+         * @param profileId the profile id to set for the APN
+         * @hide
+         */
+        public Builder setProfileId(int profileId) {
+            this.mProfileId = profileId;
+            return this;
+        }
+
+        /**
+         * Sets if the APN setting is to be set in modem.
+         *
+         * @param modemCognitive if the APN setting is to be set in modem
+         * @hide
+         */
+        public Builder setModemCognitive(boolean modemCognitive) {
+            this.mModemCognitive = modemCognitive;
+            return this;
+        }
+
+        /**
+         * Sets the max connections of this APN.
+         *
+         * @param maxConns the max connections of this APN
+         * @hide
+         */
+        public Builder setMaxConns(int maxConns) {
+            this.mMaxConns = maxConns;
+            return this;
+        }
+
+        /**
+         * Sets the wait time for retry of the APN.
+         *
+         * @param waitTime the wait time for retry of the APN
+         * @hide
+         */
+        public Builder setWaitTime(int waitTime) {
+            this.mWaitTime = waitTime;
+            return this;
+        }
+
+        /**
+         * Sets the time to limit max connection for the APN.
+         *
+         * @param maxConnsTime the time to limit max connection for the APN
+         * @hide
+         */
+        public Builder setMaxConnsTime(int maxConnsTime) {
+            this.mMaxConnsTime = maxConnsTime;
+            return this;
+        }
+
+        /**
+         * Sets the MVNO match data for the APN.
+         *
+         * @param mvnoMatchData the MVNO match data for the APN
+         * @hide
+         */
+        public Builder setMvnoMatchData(String mvnoMatchData) {
+            this.mMvnoMatchData = mvnoMatchData;
+            return this;
+        }
+
+        /**
+         * Sets the entry name of the APN.
+         *
+         * @param entryName the entry name to set for the APN
+         */
+        public Builder setEntryName(String entryName) {
+            this.mEntryName = entryName;
+            return this;
+        }
+
+        /**
+         * Sets the name of the APN.
+         *
+         * @param apnName the name to set for the APN
+         */
+        public Builder setApnName(String apnName) {
+            this.mApnName = apnName;
+            return this;
+        }
+
+        /**
+         * Sets the proxy address of the APN.
+         *
+         * @param proxy the proxy address to set for the APN
+         */
+        public Builder setProxy(InetAddress proxy) {
+            this.mProxy = proxy;
+            return this;
+        }
+
+        /**
+         * Sets the proxy port of the APN.
+         *
+         * @param port the proxy port to set for the APN
+         */
+        public Builder setPort(int port) {
+            this.mPort = port;
+            return this;
+        }
+
+        /**
+         * Sets the MMSC URL of the APN.
+         *
+         * @param mmsc the MMSC URL to set for the APN
+         */
+        public Builder setMmsc(URL mmsc) {
+            this.mMmsc = mmsc;
+            return this;
+        }
+
+        /**
+         * Sets the MMS proxy address of the APN.
+         *
+         * @param mmsProxy the MMS proxy address to set for the APN
+         */
+        public Builder setMmsProxy(InetAddress mmsProxy) {
+            this.mMmsProxy = mmsProxy;
+            return this;
+        }
+
+        /**
+         * Sets the MMS proxy port of the APN.
+         *
+         * @param mmsPort the MMS proxy port to set for the APN
+         */
+        public Builder setMmsPort(int mmsPort) {
+            this.mMmsPort = mmsPort;
+            return this;
+        }
+
+        /**
+         * Sets the APN username of the APN.
+         *
+         * @param user the APN username to set for the APN
+         */
+        public Builder setUser(String user) {
+            this.mUser = user;
+            return this;
+        }
+
+        /**
+         * Sets the APN password of the APN.
+         *
+         * @see android.provider.Telephony.Carriers#PASSWORD
+         * @param password the APN password to set for the APN
+         */
+        public Builder setPassword(String password) {
+            this.mPassword = password;
+            return this;
+        }
+
+        /**
+         * Sets the authentication type of the APN.
+         *
+         * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}.
+         *
+         * @param authType the authentication type to set for the APN
+         */
+        public Builder setAuthType(@AuthType int authType) {
+            this.mAuthType = authType;
+            return this;
+        }
+
+        /**
+         * Sets the list of APN types of the APN.
+         *
+         * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}.
+         *
+         * @param types the list of APN types to set for the APN
+         */
+        public Builder setTypes(@ApnType List<String> types) {
+            this.mTypes = types;
+            int apnBitmap = 0;
+            for (int i = 0; i < mTypes.size(); i++) {
+                mTypes.set(i, mTypes.get(i).toLowerCase());
+                apnBitmap |= getApnBitmask(mTypes.get(i));
+            }
+            this.mTypesBitmap = apnBitmap;
+            return this;
+        }
+
+        /**
+         * Sets the unique database id for this entry.
+         *
+         * @param id the unique database id to set for this entry
+         */
+        public Builder setId(int id) {
+            this.mId = id;
+            return this;
+        }
+
+        /**
+         * Set the numeric operator ID for the APN.
+         *
+         * @param operatorNumeric the numeric operator ID to set for this entry
+         */
+        public Builder setOperatorNumeric(String operatorNumeric) {
+            this.mOperatorNumeric = operatorNumeric;
+            return this;
+        }
+
+        /**
+         * Sets the protocol to use to connect to this APN.
+         *
+         * One of the {@code PDP_type} values in TS 27.007 section 10.1.1.
+         * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}.
+         *
+         * @param protocol the protocol to set to use to connect to this APN
+         */
+        public Builder setProtocol(@ProtocolType String protocol) {
+            this.mProtocol = protocol;
+            return this;
+        }
+
+        /**
+         * Sets the protocol to use to connect to this APN when roaming.
+         *
+         * @param roamingProtocol the protocol to set to use to connect to this APN when roaming
+         */
+        public Builder setRoamingProtocol(String roamingProtocol) {
+            this.mRoamingProtocol = roamingProtocol;
+            return this;
+        }
+
+        /**
+         * Sets the current status of APN.
+         *
+         * @param carrierEnabled the current status to set for this APN
+         */
+        public Builder setCarrierEnabled(boolean carrierEnabled) {
+            this.mCarrierEnabled = carrierEnabled;
+            return this;
+        }
+
+        /**
+         * Sets the MVNO match type for this APN.
+         *
+         * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}.
+         *
+         * @param mvnoType the MVNO match type to set for this APN
+         */
+        public Builder setMvnoType(@MvnoType String mvnoType) {
+            this.mMvnoType = mvnoType;
+            return this;
+        }
+
+        public ApnSetting build() {
+            return new ApnSetting(this);
+        }
+    }
+}
+
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index da51c86..ef3a183 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.net.LinkAddress;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -40,7 +41,7 @@
     private final int mActive;
     private final String mType;
     private final String mIfname;
-    private final List<InterfaceAddress> mAddresses;
+    private final List<LinkAddress> mAddresses;
     private final List<InetAddress> mDnses;
     private final List<InetAddress> mGateways;
     private final List<String> mPcscfs;
@@ -71,7 +72,7 @@
      */
     public DataCallResponse(int status, int suggestedRetryTime, int cid, int active,
                             @Nullable String type, @Nullable String ifname,
-                            @Nullable List<InterfaceAddress> addresses,
+                            @Nullable List<LinkAddress> addresses,
                             @Nullable List<InetAddress> dnses,
                             @Nullable List<InetAddress> gateways,
                             @Nullable List<String> pcscfs, int mtu) {
@@ -96,7 +97,7 @@
         mType = source.readString();
         mIfname = source.readString();
         mAddresses = new ArrayList<>();
-        source.readList(mAddresses, InterfaceAddress.class.getClassLoader());
+        source.readList(mAddresses, LinkAddress.class.getClassLoader());
         mDnses = new ArrayList<>();
         source.readList(mDnses, InetAddress.class.getClassLoader());
         mGateways = new ArrayList<>();
@@ -140,10 +141,10 @@
     public String getIfname() { return mIfname; }
 
     /**
-     * @return A list of {@link InterfaceAddress}
+     * @return A list of {@link LinkAddress}
      */
     @NonNull
-    public List<InterfaceAddress> getAddresses() { return mAddresses; }
+    public List<LinkAddress> getAddresses() { return mAddresses; }
 
     /**
      * @return A list of DNS server addresses, e.g., "192.0.1.3" or
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.java b/telephony/java/android/telephony/data/InterfaceAddress.java
deleted file mode 100644
index 00d212a..0000000
--- a/telephony/java/android/telephony/data/InterfaceAddress.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.data;
-
-import android.annotation.SystemApi;
-import android.net.NetworkUtils;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * This class represents a Network Interface address. In short it's an IP address, a subnet mask
- * when the address is an IPv4 one. An IP address and a network prefix length in the case of IPv6
- * address.
- *
- * @hide
- */
-@SystemApi
-public final class InterfaceAddress implements Parcelable {
-
-    private final InetAddress mInetAddress;
-
-    private final int mPrefixLength;
-
-    /**
-     * @param inetAddress A {@link InetAddress} of the address
-     * @param prefixLength The network prefix length for this address.
-     */
-    public InterfaceAddress(InetAddress inetAddress, int prefixLength) {
-        mInetAddress = inetAddress;
-        mPrefixLength = prefixLength;
-    }
-
-    /**
-     * @param address The address in string format
-     * @param prefixLength The network prefix length for this address.
-     * @throws UnknownHostException
-     */
-    public InterfaceAddress(String address, int prefixLength) throws UnknownHostException {
-        InetAddress ia;
-        try {
-            ia = NetworkUtils.numericToInetAddress(address);
-        } catch (IllegalArgumentException e) {
-            throw new UnknownHostException("Non-numeric ip addr=" + address);
-        }
-        mInetAddress = ia;
-        mPrefixLength = prefixLength;
-    }
-
-    public InterfaceAddress(Parcel source) {
-        mInetAddress = (InetAddress) source.readSerializable();
-        mPrefixLength = source.readInt();
-    }
-
-    /**
-     * @return an InetAddress for this address.
-     */
-    public InetAddress getAddress() { return mInetAddress; }
-
-    /**
-     * @return The network prefix length for this address.
-     */
-    public int getNetworkPrefixLength() { return mPrefixLength; }
-
-    @Override
-    public boolean equals (Object o) {
-        if (this == o) return true;
-
-        if (o == null || !(o instanceof InterfaceAddress)) {
-            return false;
-        }
-
-        InterfaceAddress other = (InterfaceAddress) o;
-        return this.mInetAddress.equals(other.mInetAddress)
-                && this.mPrefixLength == other.mPrefixLength;
-    }
-
-    @Override
-    public int hashCode() {
-        return mInetAddress.hashCode() * 31 + mPrefixLength * 37;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public String toString() {
-        return mInetAddress + "/" + mPrefixLength;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeSerializable(mInetAddress);
-        dest.writeInt(mPrefixLength);
-    }
-
-    public static final Parcelable.Creator<InterfaceAddress> CREATOR =
-            new Parcelable.Creator<InterfaceAddress>() {
-        @Override
-        public InterfaceAddress createFromParcel(Parcel source) {
-            return new InterfaceAddress(source);
-        }
-
-        @Override
-        public InterfaceAddress[] newArray(int size) {
-            return new InterfaceAddress[size];
-        }
-    };
-}
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
new file mode 100644
index 0000000..29849c1
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.euicc;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.euicc.EuiccProfileInfo;
+import android.util.Log;
+
+import com.android.internal.telephony.euicc.IEuiccCardController;
+import com.android.internal.telephony.euicc.IGetAllProfilesCallback;
+
+/**
+ * EuiccCardManager is the application interface to an eSIM card.
+ *
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public class EuiccCardManager {
+    private static final String TAG = "EuiccCardManager";
+
+    /** Result code of execution with no error. */
+    public static final int RESULT_OK = 0;
+
+    /**
+     * Callback to receive the result of an eUICC card API.
+     *
+     * @param <T> Type of the result.
+     */
+    public interface ResultCallback<T> {
+        /**
+         * This method will be called when an eUICC card API call is completed.
+         *
+         * @param resultCode This can be {@link #RESULT_OK} or other positive values returned by the
+         *     eUICC.
+         * @param result The result object. It can be null if the {@code resultCode} is not
+         *     {@link #RESULT_OK}.
+         */
+        void onComplete(int resultCode, T result);
+    }
+
+    private final Context mContext;
+
+    /** @hide */
+    public EuiccCardManager(Context context) {
+        mContext = context;
+    }
+
+    private IEuiccCardController getIEuiccCardController() {
+        return IEuiccCardController.Stub.asInterface(
+                ServiceManager.getService("euicc_card_controller"));
+    }
+
+    /**
+     * Gets all the profiles on eUicc.
+     *
+     * @param callback the callback to get the result code and all the profiles.
+     */
+    public void getAllProfiles(ResultCallback<EuiccProfileInfo[]> callback) {
+        try {
+            getIEuiccCardController().getAllProfiles(mContext.getOpPackageName(),
+                    new IGetAllProfilesCallback.Stub() {
+                        @Override
+                        public void onComplete(int resultCode, EuiccProfileInfo[] profiles) {
+                            callback.onComplete(resultCode, profiles);
+                        }
+                    });
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling getAllProfiles", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.java b/telephony/java/android/telephony/euicc/EuiccNotification.java
new file mode 100644
index 0000000..ef3c1ce
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/EuiccNotification.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.euicc;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * This represents a signed notification which is defined in SGP.22. It can be either a profile
+ * installation result or a notification generated for profile operations (e.g., enabling,
+ * disabling, or deleting).
+ *
+ * @hide
+ *
+ * TODO(b/35851809): Make this a @SystemApi.
+ */
+public class EuiccNotification implements Parcelable {
+    /** Event */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "EVENT_" }, value = {
+            EVENT_INSTALL,
+            EVENT_ENABLE,
+            EVENT_DISABLE,
+            EVENT_DELETE
+    })
+    public @interface Event {}
+
+    /** A profile is downloaded and installed. */
+    public static final int EVENT_INSTALL = 1;
+
+    /** A profile is enabled. */
+    public static final int EVENT_ENABLE = 1 << 1;
+
+    /** A profile is disabled. */
+    public static final int EVENT_DISABLE = 1 << 2;
+
+    /** A profile is deleted. */
+    public static final int EVENT_DELETE = 1 << 3;
+
+    /** Value of the bits of all above events */
+    @Event
+    public static final int ALL_EVENTS =
+            EVENT_INSTALL | EVENT_ENABLE | EVENT_DISABLE | EVENT_DELETE;
+
+    private final int mSeq;
+    private final String mTargetAddr;
+    @Event private final int mEvent;
+    @Nullable private final byte[] mData;
+
+    /**
+     * Creates an instance.
+     *
+     * @param seq The sequence number of this notification.
+     * @param targetAddr The target server where to send this notification.
+     * @param event The event which causes this notification.
+     * @param data The data which needs to be sent to the target server. This can be null for
+     *     building a list of notification metadata without data.
+     */
+    public EuiccNotification(int seq, String targetAddr, @Event int event, @Nullable byte[] data) {
+        mSeq = seq;
+        mTargetAddr = targetAddr;
+        mEvent = event;
+        mData = data;
+    }
+
+    /** @return The sequence number of this notification. */
+    public int getSeq() {
+        return mSeq;
+    }
+
+    /** @return The target server address where this notification should be sent to. */
+    public String getTargetAddr() {
+        return mTargetAddr;
+    }
+
+    /** @return The event of this notification. */
+    @Event
+    public int getEvent() {
+        return mEvent;
+    }
+
+    /** @return The notification data which needs to be sent to the target server. */
+    @Nullable
+    public byte[] getData() {
+        return mData;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+
+        EuiccNotification that = (EuiccNotification) obj;
+        return mSeq == that.mSeq
+                && Objects.equals(mTargetAddr, that.mTargetAddr)
+                && mEvent == that.mEvent
+                && Arrays.equals(mData, that.mData);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = 31 * result + mSeq;
+        result = 31 * result + Objects.hashCode(mTargetAddr);
+        result = 31 * result + mEvent;
+        result = 31 * result + Arrays.hashCode(mData);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "EuiccNotification (seq="
+                + mSeq
+                + ", targetAddr="
+                + mTargetAddr
+                + ", event="
+                + mEvent
+                + ", data="
+                + (mData == null ? "null" : "byte[" + mData.length + "]")
+                + ")";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSeq);
+        dest.writeString(mTargetAddr);
+        dest.writeInt(mEvent);
+        dest.writeByteArray(mData);
+    }
+
+    private EuiccNotification(Parcel source) {
+        mSeq = source.readInt();
+        mTargetAddr = source.readString();
+        mEvent = source.readInt();
+        mData = source.createByteArray();
+    }
+
+    public static final Creator<EuiccNotification> CREATOR =
+            new Creator<EuiccNotification>() {
+                @Override
+                public EuiccNotification createFromParcel(Parcel source) {
+                    return new EuiccNotification(source);
+                }
+
+                @Override
+                public EuiccNotification[] newArray(int size) {
+                    return new EuiccNotification[size];
+                }
+            };
+}
diff --git a/telephony/java/android/telephony/euicc/EuiccRat.java b/telephony/java/android/telephony/euicc/EuiccRat.java
new file mode 100644
index 0000000..6a56503a
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/EuiccRat.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.euicc;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.carrier.CarrierIdentifier;
+import android.service.euicc.EuiccProfileInfo;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/**
+ * This represents the RAT (Rules Authorisation Table) stored on eUICC.
+ *
+ * @hide
+ *
+ * TODO(b/35851809): Make this a @SystemApi.
+ */
+public final class EuiccRat implements Parcelable {
+    /** Profile policy rule flags */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = {
+            POLICY_RULE_FLAG_CONSENT_REQUIRED
+    })
+    public @interface PolicyRuleFlag {}
+
+    /** User consent is required to install the profile. */
+    public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1;
+
+    private final int[] mPolicyRules;
+    private final CarrierIdentifier[][] mCarrierIds;
+    private final int[] mPolicyRuleFlags;
+
+    /** This is used to build new {@link EuiccRat} instance. */
+    public static final class Builder {
+        private int[] mPolicyRules;
+        private CarrierIdentifier[][] mCarrierIds;
+        private int[] mPolicyRuleFlags;
+        private int mPosition;
+
+        /**
+         * Creates a new builder.
+         *
+         * @param ruleNum The number of authorisation rules in the table.
+         */
+        public Builder(int ruleNum) {
+            mPolicyRules = new int[ruleNum];
+            mCarrierIds = new CarrierIdentifier[ruleNum][];
+            mPolicyRuleFlags = new int[ruleNum];
+        }
+
+        /**
+         * Builds the RAT instance. This builder should not be used anymore after this method is
+         * called, otherwise {@link NullPointerException} will be thrown.
+         */
+        public EuiccRat build() {
+            if (mPosition != mPolicyRules.length) {
+                throw new IllegalStateException(
+                        "Not enough rules are added, expected: "
+                                + mPolicyRules.length
+                                + ", added: "
+                                + mPosition);
+            }
+            return new EuiccRat(mPolicyRules, mCarrierIds, mPolicyRuleFlags);
+        }
+
+        /**
+         * Adds an authorisation rule.
+         *
+         * @throws ArrayIndexOutOfBoundsException If the {@code mPosition} is larger than the size
+         *     this table.
+         */
+        public Builder add(int policyRules, CarrierIdentifier[] carrierId, int policyRuleFlags) {
+            if (mPosition >= mPolicyRules.length) {
+                throw new ArrayIndexOutOfBoundsException(mPosition);
+            }
+            mPolicyRules[mPosition] = policyRules;
+            mCarrierIds[mPosition] = carrierId;
+            mPolicyRuleFlags[mPosition] = policyRuleFlags;
+            mPosition++;
+            return this;
+        }
+    }
+
+    /**
+     * @param mccRule A 2-character or 3-character string which can be either MCC or MNC. The
+     *     character 'E' is used as a wild char to match any digit.
+     * @param mcc A 2-character or 3-character string which can be either MCC or MNC.
+     * @return Whether the {@code mccRule} matches {@code mcc}.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static boolean match(String mccRule, String mcc) {
+        if (mccRule.length() < mcc.length()) {
+            return false;
+        }
+        for (int i = 0; i < mccRule.length(); i++) {
+            // 'E' is the wild char to match any digit.
+            if (mccRule.charAt(i) == 'E'
+                    || (i < mcc.length() && mccRule.charAt(i) == mcc.charAt(i))) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    private EuiccRat(int[] policyRules, CarrierIdentifier[][] carrierIds, int[] policyRuleFlags) {
+        mPolicyRules = policyRules;
+        mCarrierIds = carrierIds;
+        mPolicyRuleFlags = policyRuleFlags;
+    }
+
+    /**
+     * Finds the index of the first authorisation rule matching the given policy and carrier id. If
+     * the returned index is not negative, the carrier is allowed to apply this policy to its
+     * profile.
+     *
+     * @param policy The policy rule.
+     * @param carrierId The carrier id.
+     * @return The index of authorization rule. If no rule is found, -1 will be returned.
+     */
+    public int findIndex(@EuiccProfileInfo.PolicyRule int policy, CarrierIdentifier carrierId) {
+        for (int i = 0; i < mPolicyRules.length; i++) {
+            if ((mPolicyRules[i] & policy) == 0) {
+                continue;
+            }
+            CarrierIdentifier[] carrierIds = mCarrierIds[i];
+            if (carrierIds == null || carrierIds.length == 0) {
+                continue;
+            }
+            for (int j = 0; j < carrierIds.length; j++) {
+                CarrierIdentifier ruleCarrierId = carrierIds[j];
+                if (!match(ruleCarrierId.getMcc(), carrierId.getMcc())
+                        || !match(ruleCarrierId.getMnc(), carrierId.getMnc())) {
+                    continue;
+                }
+                String gid = ruleCarrierId.getGid1();
+                if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid1())) {
+                    continue;
+                }
+                gid = ruleCarrierId.getGid2();
+                if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid2())) {
+                    continue;
+                }
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Tests if the entry in the table has the given policy rule flag.
+     *
+     * @param index The index of the entry.
+     * @param flag The policy rule flag to be tested.
+     * @throws ArrayIndexOutOfBoundsException If the {@code index} is negative or larger than the
+     *     size of this table.
+     */
+    public boolean hasPolicyRuleFlag(int index, @PolicyRuleFlag int flag) {
+        if (index < 0 || index >= mPolicyRules.length) {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+        return (mPolicyRuleFlags[index] & flag) != 0;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeIntArray(mPolicyRules);
+        for (CarrierIdentifier[] ids : mCarrierIds) {
+            dest.writeTypedArray(ids, flags);
+        }
+        dest.writeIntArray(mPolicyRuleFlags);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+
+        EuiccRat that = (EuiccRat) obj;
+        if (mCarrierIds.length != that.mCarrierIds.length) {
+            return false;
+        }
+        for (int i = 0; i < mCarrierIds.length; i++) {
+            CarrierIdentifier[] carrierIds = mCarrierIds[i];
+            CarrierIdentifier[] thatCarrierIds = that.mCarrierIds[i];
+            if (carrierIds != null && thatCarrierIds != null) {
+                if (carrierIds.length != thatCarrierIds.length) {
+                    return false;
+                }
+                for (int j = 0; j < carrierIds.length; j++) {
+                    if (!carrierIds[j].equals(thatCarrierIds[j])) {
+                        return false;
+                    }
+                }
+                continue;
+            } else if (carrierIds == null && thatCarrierIds == null) {
+                continue;
+            }
+            return false;
+        }
+
+        return Arrays.equals(mPolicyRules, that.mPolicyRules)
+                && Arrays.equals(mPolicyRuleFlags, that.mPolicyRuleFlags);
+    }
+
+    private EuiccRat(Parcel source) {
+        mPolicyRules = source.createIntArray();
+        int len = mPolicyRules.length;
+        mCarrierIds = new CarrierIdentifier[len][];
+        for (int i = 0; i < len; i++) {
+            mCarrierIds[i] = source.createTypedArray(CarrierIdentifier.CREATOR);
+        }
+        mPolicyRuleFlags = source.createIntArray();
+    }
+
+    public static final Creator<EuiccRat> CREATOR =
+            new Creator<EuiccRat>() {
+                @Override
+                public EuiccRat createFromParcel(Parcel source) {
+                    return new EuiccRat(source);
+                }
+
+                @Override
+                public EuiccRat[] newArray(int size) {
+                    return new EuiccRat[size];
+                }
+            };
+}
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 8230eaf..aaa0f08 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -26,12 +26,14 @@
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MMTelFeature;
 import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.ims.internal.IImsFeatureStatusCallback;
 import com.android.ims.internal.IImsMMTelFeature;
 import com.android.ims.internal.IImsRcsFeature;
+import com.android.ims.internal.IImsRegistration;
 import com.android.ims.internal.IImsServiceController;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -113,6 +115,12 @@
                 throws RemoteException {
             ImsService.this.removeImsFeature(slotId, featureType, c);
         }
+
+        @Override
+        public IImsRegistration getRegistration(int slotId) throws RemoteException {
+            ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
+            return r != null ? r.getBinder() : null;
+        }
     };
 
     /**
@@ -174,6 +182,8 @@
         f.setSlotId(slotId);
         f.addImsFeatureStatusCallback(c);
         addImsFeature(slotId, featureType, f);
+        // TODO: Remove once new onFeatureReady AIDL is merged in.
+        f.onFeatureReady();
     }
 
     private void addImsFeature(int slotId, int featureType, ImsFeature f) {
@@ -236,4 +246,13 @@
     public @Nullable RcsFeature onCreateRcsFeature(int slotId) {
         return null;
     }
+
+    /**
+     * @param slotId The slot that is associated with the IMS Registration.
+     * @return the ImsRegistration implementation associated with the slot.
+     * @hide
+     */
+    public ImsRegistrationImplBase getRegistration(int slotId) {
+        return new ImsRegistrationImplBase();
+    }
 }
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index ca4a210..d47cea30 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -96,7 +96,7 @@
             new WeakHashMap<IImsFeatureStatusCallback, Boolean>());
     private @ImsState int mState = STATE_NOT_AVAILABLE;
     private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-    private Context mContext;
+    protected Context mContext;
 
     public void setContext(Context context) {
         mContext = context;
diff --git a/telephony/java/android/telephony/ims/internal/ImsService.java b/telephony/java/android/telephony/ims/internal/ImsService.java
index b7c8ca0..afaf332 100644
--- a/telephony/java/android/telephony/ims/internal/ImsService.java
+++ b/telephony/java/android/telephony/ims/internal/ImsService.java
@@ -24,7 +24,6 @@
 import android.telephony.ims.internal.aidl.IImsConfig;
 import android.telephony.ims.internal.aidl.IImsMmTelFeature;
 import android.telephony.ims.internal.aidl.IImsRcsFeature;
-import android.telephony.ims.internal.aidl.IImsRegistration;
 import android.telephony.ims.internal.aidl.IImsServiceController;
 import android.telephony.ims.internal.aidl.IImsServiceControllerListener;
 import android.telephony.ims.internal.feature.ImsFeature;
@@ -32,11 +31,12 @@
 import android.telephony.ims.internal.feature.RcsFeature;
 import android.telephony.ims.internal.stub.ImsConfigImplBase;
 import android.telephony.ims.internal.stub.ImsFeatureConfiguration;
-import android.telephony.ims.internal.stub.ImsRegistrationImplBase;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.ims.internal.IImsRegistration;
 import com.android.internal.annotations.VisibleForTesting;
 
 /**
diff --git a/telephony/java/android/telephony/ims/internal/SmsImplBase.java b/telephony/java/android/telephony/ims/internal/SmsImplBase.java
index 47414cf..eb805a8 100644
--- a/telephony/java/android/telephony/ims/internal/SmsImplBase.java
+++ b/telephony/java/android/telephony/ims/internal/SmsImplBase.java
@@ -124,70 +124,79 @@
    * method should be implemented by the IMS providers to provide implementation of sending an SMS
    * over IMS.
    *
-   * @param smsc the Short Message Service Center address.
-   * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
-   * {@link SmsMessage#FORMAT_3GPP2}.
+   * @param token unique token generated by the platform that should be used when triggering
+   *             callbacks for this specific message.
    * @param messageRef the message reference.
+   * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
+   * @param smsc the Short Message Service Center address.
+   * {@link SmsMessage#FORMAT_3GPP2}.
    * @param isRetry whether it is a retry of an already attempted message or not.
    * @param pdu PDUs representing the contents of the message.
    */
-  public void sendSms(int messageRef, String format, String smsc, boolean isRetry, byte[] pdu) {
+  public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry,
+                      byte[] pdu) {
     // Base implementation returns error. Should be overridden.
     try {
-      onSendSmsResult(messageRef, SEND_STATUS_ERROR, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
+      onSendSmsResult(token, messageRef, SEND_STATUS_ERROR,
+              SmsManager.RESULT_ERROR_GENERIC_FAILURE);
     } catch (RemoteException e) {
       Log.e(LOG_TAG, "Can not send sms: " + e.getMessage());
     }
   }
 
   /**
-   * This method will be triggered by the platform after {@link #onSmsReceived(String, byte[])} has
-   * been called to deliver the result to the IMS provider.
+   * This method will be triggered by the platform after {@link #onSmsReceived(int, String, byte[])}
+   * has been called to deliver the result to the IMS provider.
    *
+   * @param token token provided in {@link #onSmsReceived(int, String, byte[])}
    * @param result result of delivering the message. Valid values are defined in
    * {@link DeliverStatusResult}
-   * @param messageRef the message reference or -1 of unavailable.
+   * @param messageRef the message reference
    */
-  public void acknowledgeSms(int messageRef, @DeliverStatusResult int result) {
+  public void acknowledgeSms(int token, int messageRef, @DeliverStatusResult int result) {
 
   }
 
   /**
    * This method will be triggered by the platform after
-   * {@link #onSmsStatusReportReceived(int, int, byte[])} has been called to provide the result to
-   * the IMS provider.
+   * {@link #onSmsStatusReportReceived(int, int, String, byte[])} has been called to provide the
+   * result to the IMS provider.
    *
+   * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
    * @param result result of delivering the message. Valid values are defined in
    * {@link StatusReportResult}
-   * @param messageRef the message reference or -1 of unavailable.
+   * @param messageRef the message reference
    */
-  public void acknowledgeSmsReport(int messageRef, @StatusReportResult int result) {
+  public void acknowledgeSmsReport(int token, int messageRef, @StatusReportResult int result) {
 
   }
 
   /**
    * This method should be triggered by the IMS providers when there is an incoming message. The
    * platform will deliver the message to the messages database and notify the IMS provider of the
-   * result by calling {@link #acknowledgeSms(int, int)}.
+   * result by calling {@link #acknowledgeSms(int, int, int)}.
    *
    * This method must not be called before {@link MmTelFeature#onFeatureReady()} is called.
    *
+   * @param token unique token generated by IMS providers that the platform will use to trigger
+   *              callbacks for this message.
    * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
    * {@link SmsMessage#FORMAT_3GPP2}.
    * @param pdu PDUs representing the contents of the message.
    * @throws IllegalStateException if called before {@link MmTelFeature#onFeatureReady()}
    */
-  public final void onSmsReceived(String format, byte[] pdu) throws IllegalStateException {
+  public final void onSmsReceived(int token, String format, byte[] pdu)
+          throws IllegalStateException {
     synchronized (mLock) {
       if (mListener == null) {
         throw new IllegalStateException("Feature not ready.");
       }
       try {
-        mListener.onSmsReceived(format, pdu);
-        acknowledgeSms(-1, DELIVER_STATUS_OK);
+        mListener.onSmsReceived(token, format, pdu);
+        acknowledgeSms(token, 0, DELIVER_STATUS_OK);
       } catch (RemoteException e) {
         Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage());
-        acknowledgeSms(-1, DELIVER_STATUS_ERROR);
+        acknowledgeSms(token, 0, DELIVER_STATUS_ERROR);
       }
     }
   }
@@ -198,6 +207,7 @@
    *
    * This method must not be called before {@link MmTelFeature#onFeatureReady()} is called.
    *
+   * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
    * @param messageRef the message reference. Should be between 0 and 255 per TS.123.040
    * @param status result of sending the SMS. Valid values are defined in {@link SendStatusResult}
    * @param reason reason in case status is failure. Valid values are:
@@ -213,35 +223,37 @@
    * @throws RemoteException if the connection to the framework is not available. If this happens
    *  attempting to send the SMS should be aborted.
    */
-  public final void onSendSmsResult(int messageRef, @SendStatusResult int status, int reason)
-      throws IllegalStateException, RemoteException {
+  public final void onSendSmsResult(int token, int messageRef, @SendStatusResult int status,
+      int reason) throws IllegalStateException, RemoteException {
     synchronized (mLock) {
       if (mListener == null) {
         throw new IllegalStateException("Feature not ready.");
       }
-      mListener.onSendSmsResult(messageRef, status, reason);
+      mListener.onSendSmsResult(token, messageRef, status, reason);
     }
   }
 
   /**
    * Sets the status report of the sent message.
    *
+   * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
    * @param messageRef the message reference.
    * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
    * {@link SmsMessage#FORMAT_3GPP2}.
    * @param pdu PDUs representing the content of the status report.
    * @throws IllegalStateException if called before {@link MmTelFeature#onFeatureReady()}
    */
-  public final void onSmsStatusReportReceived(int messageRef, String format, byte[] pdu) {
+  public final void onSmsStatusReportReceived(int token, int messageRef, String format,
+      byte[] pdu) {
     synchronized (mLock) {
       if (mListener == null) {
         throw new IllegalStateException("Feature not ready.");
       }
       try {
-        mListener.onSmsStatusReportReceived(messageRef, format, pdu);
+        mListener.onSmsStatusReportReceived(token, messageRef, format, pdu);
       } catch (RemoteException e) {
         Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
-        acknowledgeSmsReport(messageRef, STATUS_REPORT_STATUS_ERROR);
+        acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR);
       }
     }
   }
diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl
index d976686..785113f 100644
--- a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl
+++ b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl
@@ -52,8 +52,9 @@
             IImsCapabilityCallback c);
     // SMS APIs
     void setSmsListener(IImsSmsListener l);
-    oneway void sendSms(int messageRef, String format, String smsc, boolean retry, in byte[] pdu);
-    oneway void acknowledgeSms(int messageRef, int result);
-    oneway void acknowledgeSmsReport(int messageRef, int result);
+    oneway void sendSms(in int token, int messageRef, String format, String smsc, boolean retry,
+            in byte[] pdu);
+    oneway void acknowledgeSms(int token, int messageRef, int result);
+    oneway void acknowledgeSmsReport(int token, int messageRef, int result);
     String getSmsFormat();
 }
diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl
index 8332bc0..43f5098 100644
--- a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl
+++ b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl
@@ -24,4 +24,5 @@
  */
 oneway interface IImsMmTelListener {
     void onIncomingCall(IImsCallSession c);
+    void onVoiceMessageCountUpdate(int count);
 }
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl
index 8afb955..82a8525 100644
--- a/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl
+++ b/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl
@@ -18,12 +18,12 @@
 
 import android.telephony.ims.internal.aidl.IImsMmTelFeature;
 import android.telephony.ims.internal.aidl.IImsRcsFeature;
-import android.telephony.ims.internal.aidl.IImsRegistration;
 import android.telephony.ims.internal.aidl.IImsConfig;
 import android.telephony.ims.internal.aidl.IImsServiceControllerListener;
 import android.telephony.ims.internal.stub.ImsFeatureConfiguration;
 
 import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.ims.internal.IImsRegistration;
 
 /**
  * See ImsService and MmTelFeature for more information.
diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl
index 468629a..bf8d90b 100644
--- a/telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl
+++ b/telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl
@@ -21,7 +21,8 @@
  * {@hide}
  */
 interface IImsSmsListener {
-    void onSendSmsResult(in int messageRef, in int status, in int reason);
-    void onSmsStatusReportReceived(in int messageRef, in String format, in byte[] pdu);
-    void onSmsReceived(in String format, in byte[] pdu);
+    void onSendSmsResult(in int token, in int messageRef, in int status, in int reason);
+    void onSmsStatusReportReceived(in int token, in int messageRef, in String format,
+            in byte[] pdu);
+    void onSmsReceived(in int token, in String format, in byte[] pdu);
 }
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java
index 4d18873..5dbf077 100644
--- a/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java
@@ -18,7 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.ims.internal.stub.ImsRegistrationImplBase;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.ArraySet;
 
 import java.util.ArrayList;
diff --git a/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java
index 2f350c8..8d888c2 100644
--- a/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java
@@ -28,8 +28,8 @@
 import android.telephony.ims.internal.aidl.IImsCapabilityCallback;
 import android.telephony.ims.internal.aidl.IImsMmTelFeature;
 import android.telephony.ims.internal.aidl.IImsMmTelListener;
-import android.telephony.ims.internal.stub.ImsRegistrationImplBase;
 import android.telephony.ims.internal.aidl.IImsSmsListener;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.telephony.ims.stub.ImsEcbmImplBase;
 import android.telephony.ims.stub.ImsMultiEndpointImplBase;
 import android.telephony.ims.stub.ImsUtImplBase;
@@ -154,23 +154,24 @@
         }
 
         @Override
-        public void sendSms(int messageRef, String format, String smsc, boolean retry, byte[] pdu) {
+        public void sendSms(int token, int messageRef, String format, String smsc, boolean retry,
+                byte[] pdu) {
             synchronized (mLock) {
-                MmTelFeature.this.sendSms(messageRef, format, smsc, retry, pdu);
+                MmTelFeature.this.sendSms(token, messageRef, format, smsc, retry, pdu);
             }
         }
 
         @Override
-        public void acknowledgeSms(int messageRef, int result) {
+        public void acknowledgeSms(int token, int messageRef, int result) {
             synchronized (mLock) {
-                MmTelFeature.this.acknowledgeSms(messageRef, result);
+                MmTelFeature.this.acknowledgeSms(token, messageRef, result);
             }
         }
 
         @Override
-        public void acknowledgeSmsReport(int messageRef, int result) {
+        public void acknowledgeSmsReport(int token, int messageRef, int result) {
             synchronized (mLock) {
-                MmTelFeature.this.acknowledgeSmsReport(messageRef, result);
+                MmTelFeature.this.acknowledgeSmsReport(token, messageRef, result);
             }
         }
 
@@ -261,6 +262,15 @@
         }
 
         /**
+         * Updates the Listener when the voice message count for IMS has changed.
+         * @param count an integer representing the new message count.
+         */
+        @Override
+        public void onVoiceMessageCountUpdate(int count) {
+
+        }
+
+        /**
          * Called when the IMS provider receives an incoming call.
          * @param c The {@link ImsCallSession} associated with the new call.
          */
@@ -447,16 +457,17 @@
         // Base Implementation - Should be overridden
     }
 
-    private void sendSms(int messageRef, String format, String smsc, boolean isRetry, byte[] pdu) {
-        getSmsImplementation().sendSms(messageRef, format, smsc, isRetry, pdu);
+    private void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry,
+            byte[] pdu) {
+        getSmsImplementation().sendSms(token, messageRef, format, smsc, isRetry, pdu);
     }
 
-    private void acknowledgeSms(int messageRef, @DeliverStatusResult int result) {
-        getSmsImplementation().acknowledgeSms(messageRef, result);
+    private void acknowledgeSms(int token, int messageRef, @DeliverStatusResult int result) {
+        getSmsImplementation().acknowledgeSms(token, messageRef, result);
     }
 
-    private void acknowledgeSmsReport(int messageRef, @StatusReportResult int result) {
-        getSmsImplementation().acknowledgeSmsReport(messageRef, result);
+    private void acknowledgeSmsReport(int token, int messageRef, @StatusReportResult int result) {
+        getSmsImplementation().acknowledgeSmsReport(token, messageRef, result);
     }
 
     private String getSmsFormat() {
diff --git a/telephony/java/android/telephony/ims/internal/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
similarity index 83%
rename from telephony/java/android/telephony/ims/internal/stub/ImsRegistrationImplBase.java
rename to telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 558b009..42af083 100644
--- a/telephony/java/android/telephony/ims/internal/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -14,16 +14,19 @@
  * limitations under the License
  */
 
-package android.telephony.ims.internal.stub;
+package android.telephony.ims.stub;
 
 import android.annotation.IntDef;
+import android.net.Uri;
+import android.os.IBinder;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.telephony.ims.internal.aidl.IImsRegistration;
-import android.telephony.ims.internal.aidl.IImsRegistrationCallback;
 import android.util.Log;
 
 import com.android.ims.ImsReasonInfo;
+import com.android.ims.internal.IImsRegistration;
+import com.android.ims.internal.IImsRegistrationCallback;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -62,23 +65,25 @@
 
     // Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current
     // state.
+    // The unknown state is set as the initialization state. This is so that we do not call back
+    // with NOT_REGISTERED in the case where the ImsService has not updated the registration state
+    // yet.
+    private static final int REGISTRATION_STATE_UNKNOWN = -1;
     private static final int REGISTRATION_STATE_NOT_REGISTERED = 0;
     private static final int REGISTRATION_STATE_REGISTERING = 1;
     private static final int REGISTRATION_STATE_REGISTERED = 2;
 
-
     /**
      * Callback class for receiving Registration callback events.
+     * @hide
      */
-    public static class Callback extends IImsRegistrationCallback.Stub {
-
+    public static class Callback {
         /**
          * Notifies the framework when the IMS Provider is connected to the IMS network.
          *
          * @param imsRadioTech the radio access technology. Valid values are defined in
          * {@link ImsRegistrationTech}.
          */
-        @Override
         public void onRegistered(@ImsRegistrationTech int imsRadioTech) {
         }
 
@@ -88,7 +93,6 @@
          * @param imsRadioTech the radio access technology. Valid values are defined in
          * {@link ImsRegistrationTech}.
          */
-        @Override
         public void onRegistering(@ImsRegistrationTech int imsRadioTech) {
         }
 
@@ -97,7 +101,6 @@
          *
          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
          */
-        @Override
         public void onDeregistered(ImsReasonInfo info) {
         }
 
@@ -108,10 +111,19 @@
          * @param imsRadioTech The {@link ImsRegistrationTech} type that has failed
          * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
          */
-        @Override
         public void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech,
                 ImsReasonInfo info) {
         }
+
+        /**
+         * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
+         * it changes.
+         * @param uris new array of subscriber {@link Uri}s that are associated with this IMS
+         *         subscription.
+         */
+        public void onSubscriberAssociatedUriChanged(Uri[] uris) {
+
+        }
     }
 
     private final IImsRegistration mBinder = new IImsRegistration.Stub() {
@@ -139,9 +151,9 @@
     private @ImsRegistrationTech
     int mConnectionType = REGISTRATION_TECH_NONE;
     // Locked on mLock
-    private int mRegistrationState = REGISTRATION_STATE_NOT_REGISTERED;
-    // Locked on mLock
-    private ImsReasonInfo mLastDisconnectCause;
+    private int mRegistrationState = REGISTRATION_STATE_UNKNOWN;
+    // Locked on mLock, create unspecified disconnect cause.
+    private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo();
 
     public final IImsRegistration getBinder() {
         return mBinder;
@@ -221,6 +233,17 @@
         });
     }
 
+    public final void onSubscriberAssociatedUriChanged(Uri[] uris) {
+        mCallbacks.broadcast((c) -> {
+            try {
+                c.onSubscriberAssociatedUriChanged(uris);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping " +
+                        "callback.");
+            }
+        });
+    }
+
     private void updateToState(@ImsRegistrationTech int connType, int newState) {
         synchronized (mLock) {
             mConnectionType = connType;
@@ -241,7 +264,8 @@
         }
     }
 
-    private @ImsRegistrationTech int getConnectionType() {
+    @VisibleForTesting
+    public final @ImsRegistrationTech int getConnectionType() {
         synchronized (mLock) {
             return mConnectionType;
         }
@@ -271,6 +295,10 @@
                 c.onRegistered(getConnectionType());
                 break;
             }
+            case REGISTRATION_STATE_UNKNOWN: {
+                // Do not callback if the state has not been updated yet by the ImsService.
+                break;
+            }
         }
     }
 }
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 489c208..693aaff 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -351,7 +351,7 @@
         mServiceType = in.readInt();
         mCallType = in.readInt();
         mCallExtras = in.readBundle();
-        mMediaProfile = in.readParcelable(null);
+        mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader());
     }
 
     public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() {
diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl b/telephony/java/com/android/ims/internal/IImsRegistration.aidl
similarity index 82%
rename from telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl
rename to telephony/java/com/android/ims/internal/IImsRegistration.aidl
index 687b7ca..6de264e 100644
--- a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistration.aidl
@@ -15,10 +15,9 @@
  */
 
 
-package android.telephony.ims.internal.aidl;
+package com.android.ims.internal;
 
-import android.telephony.ims.internal.aidl.IImsRegistrationCallback;
-import android.telephony.ims.internal.stub.ImsFeatureConfiguration;
+import com.android.ims.internal.IImsRegistrationCallback;
 
 /**
  * See ImsRegistration for more information.
diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationCallback.aidl
similarity index 89%
rename from telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl
rename to telephony/java/com/android/ims/internal/IImsRegistrationCallback.aidl
index a50575b..5f21167 100644
--- a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationCallback.aidl
@@ -15,8 +15,9 @@
  */
 
 
-package android.telephony.ims.internal.aidl;
+package com.android.ims.internal;
 
+import android.net.Uri;
 import android.telephony.ims.internal.stub.ImsFeatureConfiguration;
 
 import com.android.ims.ImsReasonInfo;
@@ -31,4 +32,5 @@
    void onRegistering(int imsRadioTech);
    void onDeregistered(in ImsReasonInfo info);
    void onTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info);
+   void onSubscriberAssociatedUriChanged(in Uri[] uris);
 }
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index 857089f..7ac25ac 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -18,6 +18,7 @@
 
 import com.android.ims.internal.IImsFeatureStatusCallback;
 import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRegistration;
 import com.android.ims.internal.IImsRcsFeature;
 
 /**
@@ -29,4 +30,5 @@
     IImsMMTelFeature createMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
     IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c);
     void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c);
+    IImsRegistration getRegistration(int slotId);
 }
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index ac16139..8e3f4c0 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -46,5 +46,6 @@
     void onVoiceActivationStateChanged(int activationState);
     void onDataActivationStateChanged(int activationState);
     void onCarrierNetworkChange(in boolean active);
+    void onUserMobileDataStateChanged(in boolean enabled);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 0f31821..f8a040d 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -152,6 +152,13 @@
     in ImsiEncryptionInfo imsiEncryptionInfo);
 
     /**
+     * Resets the Carrier Keys in the database. This involves 2 steps:
+     *  1. Delete the keys from the database.
+     *  2. Send an intent to download new Certificates.
+     */
+    void resetCarrierKeysForImsiEncryption(int subId, String callingPackage);
+
+    /**
      * Retrieves the alpha identifier associated with the voice mail number.
      */
     String getVoiceMailAlphaTag(String callingPackage);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 416146f..fba82ee 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -40,6 +40,7 @@
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import com.android.ims.internal.IImsMMTelFeature;
 import com.android.ims.internal.IImsRcsFeature;
+import com.android.ims.internal.IImsRegistration;
 import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.OperatorInfo;
@@ -808,6 +809,11 @@
     IImsRcsFeature getRcsFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
 
     /**
+    * Returns the IImsRegistration associated with the slot and feature specified.
+    */
+    IImsRegistration getImsRegistration(int slotId, int feature);
+
+    /**
      * Set the network selection mode to automatic.
      *
      * @param subId the id of the subscription to update.
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 75d8f3f..188167c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -69,4 +69,5 @@
             int activationState, int activationType);
     void notifySubscriptionInfoChanged();
     void notifyCarrierNetworkChange(in boolean active);
+    void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state);
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index f29d993c..51369d0 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -486,4 +486,10 @@
     */
     public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE =
             "com.android.omadm.service.CONFIGURATION_UPDATE";
+
+    /**
+     * Broadcast action to trigger the Carrier Certificate download.
+     */
+    public static final String ACTION_CARRIER_CERTIFICATE_DOWNLOAD =
+            "com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD";
 }
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
similarity index 65%
copy from telephony/java/android/telephony/data/InterfaceAddress.aidl
copy to telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
index d750363..2846a1a 100644
--- a/telephony/java/android/telephony/data/InterfaceAddress.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package com.android.internal.telephony.euicc;
 
-parcelable InterfaceAddress;
+import com.android.internal.telephony.euicc.IGetAllProfilesCallback;
+
+/** @hide */
+interface IEuiccCardController {
+    oneway void getAllProfiles(String callingPackage, in IGetAllProfilesCallback callback);
+}
diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl
similarity index 68%
copy from telephony/java/android/telephony/data/InterfaceAddress.aidl
copy to telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl
index d750363..97b0768 100644
--- a/telephony/java/android/telephony/data/InterfaceAddress.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -13,8 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.internal.telephony.euicc;
+
+import android.service.euicc.EuiccProfileInfo;
 
 /** @hide */
-package android.telephony.data;
-
-parcelable InterfaceAddress;
+oneway interface IGetAllProfilesCallback {
+    void onComplete(int resultCode, in EuiccProfileInfo[] profiles);
+}
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 0088962..ccf57b0 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -49,7 +49,8 @@
 
 // Build the repackaged.android.test.base library
 // ==============================================
-// This contains repackaged versions of the classes from legacy-test.
+// This contains repackaged versions of the classes from
+// android.test.base.
 java_library_static {
     name: "repackaged.android.test.base",
 
@@ -97,7 +98,7 @@
     ],
 
     static_libs: [
-        "android.test.runner",
+        "android.test.runner-minus-junit",
         "android.test.mock",
     ],
 
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 8eddec4..b1ae40e 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -24,7 +24,6 @@
     no_framework_libs: true,
     libs: [
         "framework",
-        "legacy-test",
     ],
 }
 
diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
index 7207ebc..13e3693 100644
--- a/test-mock/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
@@ -1174,4 +1174,20 @@
     public ArtManager getArtManager() {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void setHarmfulAppWarning(String packageName, CharSequence warning) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public CharSequence getHarmfulAppWarning(String packageName) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index 104ae82..dfaeed5 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -24,11 +24,28 @@
     no_framework_libs: true,
     libs: [
         "framework",
-        "legacy-test",
+        "android.test.base",
         "android.test.mock",
     ],
 }
 
+// Build the android.test.runner-minus-junit library
+// =================================================
+// This is provided solely for use by the legacy-android-test module.
+java_library {
+    name: "android.test.runner-minus-junit",
+
+    srcs: ["src/android/**/*.java"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+        "android.test.base",
+        "android.test.mock",
+        "junit",
+    ],
+}
+
 // Build the repackaged.android.test.runner library
 // ================================================
 java_library_static {
diff --git a/tests/ActivityManagerPerfTests/README.txt b/tests/ActivityManagerPerfTests/README.txt
new file mode 100644
index 0000000..77e0e90
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/README.txt
@@ -0,0 +1,34 @@
+ActivityManagerPerfTests
+
+Performance tests for various ActivityManager components, e.g. Services, Broadcasts
+
+Command to run tests (not working yet, atest seems buggy)
+* atest .../frameworks/base/tests/ActivityManagerPerfTests
+* m ActivityManagerPerfTests ActivityManagerPerfTestsTestApp && \
+  adb install $OUT/data/app/ActivityManagerPerfTests/ActivityManagerPerfTests.apk && \
+  adb install $OUT/data/app/ActivityManagerPerfTestsTestApp/ActivityManagerPerfTestsTestApp.apk && \
+  adb shell am instrument -w \
+  com.android.frameworks.perftests.amtests/android.support.test.runner.AndroidJUnitRunner
+
+Overview
+* The numbers we are trying to measure are end-to-end numbers
+  * For example, the time it takes from sending an Intent to start a Service
+    to the time the Service runs its callbacks
+* System.nanoTime() is monotonic and consistent between processes, so we use that for measuring time
+* To make sure the test app is running, we start an Activity
+* If the test app is involved, it will measure the time and send it back to the instrumentation test
+  * The time is sent back through a Binder interface in the Intent
+  * Each sent time is tagged with an id since there can be multiple events that send back a time
+    * For example, one is sent when the Activity is started, and another could be sent when a
+      Broadcast is received
+
+Structure
+* tests
+  * Instrumentation test which runs the various performance tests and reports the results
+
+* test-app
+  * Target package which contains the Services, BroadcastReceivers, etc. to test against
+  * Sends the time it measures back to the test package
+
+* utils
+  * Utilities that both the instrumentation test and test app can use
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.mk b/tests/ActivityManagerPerfTests/test-app/Android.mk
new file mode 100644
index 0000000..b0a5db7
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/Android.mk
@@ -0,0 +1,28 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ActivityManagerPerfTestsUtils
+
+LOCAL_PACKAGE_NAME := ActivityManagerPerfTestsTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..7145110
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.frameworks.perftests.amteststestapp">
+    <application android:name=".TestApplication">
+        <activity android:name=".TestActivity" android:exported="true"/>
+        <receiver
+            android:name=".TestBroadcastReceiver"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.frameworks.perftests.ACTION_BROADCAST_MANIFEST_RECEIVE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
new file mode 100644
index 0000000..7ea9ba3
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.amteststestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.perftests.am.util.Constants;
+import com.android.frameworks.perftests.am.util.Utils;
+
+public class TestActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Utils.sendTime(getIntent(), Constants.TYPE_ACTIVITY_CREATED);
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestApplication.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestApplication.java
new file mode 100644
index 0000000..e26ffcd
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestApplication.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.amteststestapp;
+
+import android.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import com.android.frameworks.perftests.am.util.Constants;
+import com.android.frameworks.perftests.am.util.Utils;
+
+public class TestApplication extends Application {
+    private static final String TAG = TestApplication.class.getSimpleName();
+
+    @Override
+    public void onCreate() {
+        createRegisteredReceiver();
+
+        super.onCreate();
+    }
+
+    // Create registered BroadcastReceiver
+    private void createRegisteredReceiver() {
+        BroadcastReceiver registered = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                Log.i(TAG, "RegisteredReceiver.onReceive");
+                Utils.sendTime(intent, Constants.TYPE_BROADCAST_RECEIVE);
+            }
+        };
+        IntentFilter intentFilter = new IntentFilter(Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
+        registerReceiver(registered, intentFilter);
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestBroadcastReceiver.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestBroadcastReceiver.java
new file mode 100644
index 0000000..336bf9d
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestBroadcastReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.amteststestapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import com.android.frameworks.perftests.am.util.Constants;
+import com.android.frameworks.perftests.am.util.Utils;
+
+public class TestBroadcastReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Utils.sendTime(intent, Constants.TYPE_BROADCAST_RECEIVE);
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/Android.mk b/tests/ActivityManagerPerfTests/tests/Android.mk
new file mode 100644
index 0000000..daf603d
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/Android.mk
@@ -0,0 +1,33 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    apct-perftests-utils \
+    ActivityManagerPerfTestsUtils
+
+LOCAL_PACKAGE_NAME := ActivityManagerPerfTests
+
+# For android.permission.FORCE_STOP_PACKAGES permission
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml b/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml
new file mode 100644
index 0000000..4e194c6
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.perftests.amtests">
+    <uses-permission android:name="android.permission.DUMP" />
+    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.frameworks.perftests.amtests"/>
+</manifest>
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
new file mode 100644
index 0000000..ffb5404
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<configuration description="Runs ActivityManager Performance Tests">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="ActivityManagerPerfTests.apk"/>
+        <option name="test-file-name" value="ActivityManagerPerfTestsTestApp.apk"/>
+        <option name="cleanup-apks" value="true"/>
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-tag" value="ActivityManagerPerfTests"/>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.frameworks.perftests.amtests"/>
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
new file mode 100644
index 0000000..661abe9
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.tests;
+
+import android.content.Context;
+import android.content.Intent;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.PerfManualStatusReporter;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.frameworks.perftests.am.util.TargetPackageUtils;
+import com.android.frameworks.perftests.am.util.TimeReceiver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+
+import java.util.function.LongSupplier;
+
+public class BasePerfTest {
+    private static final String TAG = BasePerfTest.class.getSimpleName();
+
+    private TimeReceiver mTimeReceiver;
+
+    @Rule
+    public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
+
+    protected Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mTimeReceiver = new TimeReceiver();
+    }
+
+    @After
+    public void tearDown() {
+        TargetPackageUtils.killTargetPackage(mContext);
+    }
+
+    protected Intent createIntent(String action) {
+        final Intent intent = new Intent(action);
+        intent.addFlags(
+                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+        intent.putExtras(mTimeReceiver.createReceiveTimeExtraBinder());
+        return intent;
+    }
+
+    private void setUpIteration() {
+        mTimeReceiver.clear();
+        TargetPackageUtils.killTargetPackage(mContext);
+    }
+
+    protected void startTargetPackage() {
+        TargetPackageUtils.startTargetPackage(mContext, mTimeReceiver);
+    }
+
+    protected long getReceivedTimeNs(String type) {
+        return mTimeReceiver.getReceivedTimeNs(type);
+    }
+
+    protected void runPerfFunction(LongSupplier func) {
+        final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
+        long elapsedTimeNs = 0;
+        while (benchmarkState.keepRunning(elapsedTimeNs)) {
+            setUpIteration();
+            elapsedTimeNs = func.getAsLong();
+        }
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
new file mode 100644
index 0000000..795f498
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.tests;
+
+import android.content.Intent;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BroadcastPerfTest extends BasePerfTest {
+    @Test
+    public void manifestBroadcastRunning() {
+        runPerfFunction(() -> {
+            startTargetPackage();
+
+            final Intent intent = createIntent(Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
+
+            final long startTime = System.nanoTime();
+
+            mContext.sendBroadcast(intent);
+
+            final long endTime = getReceivedTimeNs(Constants.TYPE_BROADCAST_RECEIVE);
+
+            return endTime - startTime;
+        });
+    }
+
+    @Test
+    public void manifestBroadcastNotRunning() {
+        runPerfFunction(() -> {
+            final Intent intent = createIntent(Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
+
+            final long startTime = System.nanoTime();
+
+            mContext.sendBroadcast(intent);
+
+            final long endTime = getReceivedTimeNs(Constants.TYPE_BROADCAST_RECEIVE);
+
+            return endTime - startTime;
+        });
+    }
+
+    @Test
+    public void registeredBroadcast() {
+        runPerfFunction(() -> {
+            startTargetPackage();
+
+            final Intent intent = createIntent(Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
+
+            final long startTime = System.nanoTime();
+
+            mContext.sendBroadcast(intent);
+
+            final long endTime = getReceivedTimeNs(Constants.TYPE_BROADCAST_RECEIVE);
+
+            return endTime - startTime;
+        });
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
new file mode 100644
index 0000000..c867141
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.util;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.SystemClock;
+
+public class TargetPackageUtils {
+    private static final String TAG = TargetPackageUtils.class.getSimpleName();
+
+    public static final String PACKAGE_NAME = "com.android.frameworks.perftests.amteststestapp";
+    public static final String ACTIVITY_NAME = PACKAGE_NAME + ".TestActivity";
+
+    private static final long WAIT_TIME_MS = 100L;
+
+    // Cache for test app's uid, so we only have to query it once.
+    private static int sTestAppUid = -1;
+
+    /**
+     * Kills the test package synchronously.
+     */
+    public static void killTargetPackage(Context context) {
+        ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+        activityManager.forceStopPackage(PACKAGE_NAME);
+        while (targetPackageIsRunning(context)) {
+            sleep();
+        }
+
+        Utils.drainBroadcastQueue();
+    }
+
+    /**
+     * Starts the test package synchronously. It does so by starting an Activity.
+     */
+    public static void startTargetPackage(Context context, TimeReceiver timeReceiver) {
+        // "am start-activity -W PACKAGE_NAME/ACTIVITY_CLASS_NAME" still requires a sleep even
+        // though it should be synchronous, so just use Intent instead
+        final Intent intent = new Intent();
+        intent.putExtras(timeReceiver.createReceiveTimeExtraBinder());
+        intent.setClassName(PACKAGE_NAME, ACTIVITY_NAME);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+
+        while (!targetPackageIsRunning(context)) {
+            sleep();
+        }
+        // make sure Application has run
+        timeReceiver.getReceivedTimeNs(Constants.TYPE_ACTIVITY_CREATED);
+        Utils.drainBroadcastQueue();
+    }
+
+    private static boolean targetPackageIsRunning(Context context) {
+        final int uid = getTestAppUid(context);
+        final String result = Utils.runShellCommand(
+                String.format("cmd activity get-uid-state %d", uid));
+        return !result.contains("(NONEXISTENT)");
+    }
+
+    private static void sleep() {
+        SystemClock.sleep(WAIT_TIME_MS);
+    }
+
+    private static int getTestAppUid(Context context) {
+        if (sTestAppUid == -1) {
+            final PackageManager pm = context.getPackageManager();
+            try {
+                sTestAppUid = pm.getPackageUid(PACKAGE_NAME, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return sTestAppUid;
+    }
+
+}
+
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
new file mode 100644
index 0000000..9cf6ee7
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.util;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * TimeReceiver will listen for any messages containing a timestamp by starting a BroadcastReceiver
+ * which listens for Intents with the SendTime.ACTION_SEND_TIME action.
+ */
+public class TimeReceiver {
+    private static final String TAG = TimeReceiver.class.getSimpleName();
+    private static final long DEFAULT_RECEIVE_TIME_TIMEOUT_MILLIS = 10000L;
+
+    private BlockingQueue<ReceivedMessage> mQueue = new LinkedBlockingQueue<>();
+
+    private static class ReceivedMessage {
+        private final String mReceivedMessageType;
+        private final long mReceivedTimeNs;
+
+        public ReceivedMessage(String receivedMessageType, long receivedTimeNs) {
+            mReceivedMessageType = receivedMessageType;
+            mReceivedTimeNs = receivedTimeNs;
+        }
+    }
+
+    public Bundle createReceiveTimeExtraBinder() {
+        Bundle extras = new Bundle();
+        extras.putBinder(Constants.EXTRA_RECEIVER_CALLBACK, new ITimeReceiverCallback.Stub() {
+            @Override
+            public void sendTime(String type, long timeNs) throws RemoteException {
+                if (type == null) {
+                    throw new RuntimeException("receivedType is null");
+                }
+                if (timeNs < 0) {
+                    throw new RuntimeException(
+                            "receivedTime is negative/non-existant: " + timeNs);
+                }
+                Log.i(TAG, type + " " + timeNs);
+                mQueue.add(new ReceivedMessage(type, timeNs));
+            }
+        });
+        return extras;
+    }
+
+    public long getReceivedTimeNs(String type) {
+        return getReceivedTimeNs(type, DEFAULT_RECEIVE_TIME_TIMEOUT_MILLIS);
+    }
+
+    /**
+     * Returns a received timestamp with the given type tag. Will throw away any messages with a
+     * different type tag. If it times out, a RuntimeException is thrown.
+     */
+    public long getReceivedTimeNs(String type, long timeoutMs) {
+        ReceivedMessage message;
+        long endTimeNs = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs);
+        do {
+            long curTimeNs = System.nanoTime();
+            if (curTimeNs > endTimeNs) {
+                throw new RuntimeException("Timed out when listening for a time: " + type);
+            }
+            try {
+                Log.i(TAG, "waiting for message " + type);
+                message = mQueue.poll(endTimeNs - curTimeNs, TimeUnit.NANOSECONDS);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+            if (message == null) {
+                throw new RuntimeException("Timed out when listening for a time: " + type);
+            }
+            Log.i(TAG, "got message " + message.mReceivedMessageType);
+            if (!type.equals(message.mReceivedMessageType)) {
+                Log.i(TAG, String.format("Expected type \"%s\", got \"%s\" (%d), skipping", type,
+                        message.mReceivedMessageType, message.mReceivedTimeNs));
+            }
+        } while (!type.equals(message.mReceivedMessageType));
+        return message.mReceivedTimeNs;
+    }
+
+    /**
+     * Clears the message queue.
+     */
+    public void clear() {
+        mQueue.clear();
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/utils/Android.mk b/tests/ActivityManagerPerfTests/utils/Android.mk
new file mode 100644
index 0000000..7276e37
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/utils/Android.mk
@@ -0,0 +1,31 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    junit \
+    ub-uiautomator
+
+LOCAL_MODULE := ActivityManagerPerfTestsUtils
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
new file mode 100644
index 0000000..6528028
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.util;
+
+public class Constants {
+    public static final String TYPE_ACTIVITY_CREATED = "activity_create";
+    public static final String TYPE_BROADCAST_RECEIVE = "broadcast_receive";
+
+    public static final String ACTION_BROADCAST_MANIFEST_RECEIVE =
+            "com.android.frameworks.perftests.ACTION_BROADCAST_MANIFEST_RECEIVE";
+    public static final String ACTION_BROADCAST_REGISTERED_RECEIVE =
+            "com.android.frameworks.perftests.ACTION_BROADCAST_REGISTERED_RECEIVE";
+
+    public static final String EXTRA_RECEIVER_CALLBACK = "receiver_callback_binder";
+}
diff --git a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl
similarity index 74%
rename from core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl
rename to tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl
index fe13179..b43d49a 100644
--- a/core/java/android/security/recoverablekeystore/KeyDerivationParameters.aidl
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-package android.security.recoverablekeystore;
+package com.android.frameworks.perftests.am.util;
 
-/* @hide */
-parcelable KeyDerivationParameters;
+interface ITimeReceiverCallback {
+    void sendTime(String type, long timeNs);
+}
\ No newline at end of file
diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Utils.java b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Utils.java
new file mode 100644
index 0000000..493d8cd
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Utils.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.util;
+
+import android.content.Intent;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import java.io.IOException;
+
+public class Utils {
+    private static final String TAG = "AmPerfTestsUtils";
+
+    public static void drainBroadcastQueue() {
+        runShellCommand("am wait-for-broadcast-idle");
+    }
+
+    /**
+     * Runs the command and returns the stdout.
+     */
+    public static String runShellCommand(String cmd) {
+        try {
+            return UiDevice.getInstance(
+                    InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Sends the current time in a message with the given type so TimeReceiver can receive it.
+     */
+    public static void sendTime(Intent intent, String type) {
+        final long time = System.nanoTime();
+        final ITimeReceiverCallback sendTimeBinder = ITimeReceiverCallback.Stub.asInterface(
+                intent.getExtras().getBinder(Constants.EXTRA_RECEIVER_CALLBACK));
+        try {
+            sendTimeBinder.sendTime(type, time);
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getMessage());
+        }
+    }
+}
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 473dc538..9aad413 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -67,7 +67,7 @@
             assertEquals(msg, t.expectedType, got);
 
             if (got != MacAddress.TYPE_UNKNOWN) {
-                assertEquals(got, MacAddress.fromBytes(t.addr).addressType());
+                assertEquals(got, MacAddress.fromBytes(t.addr).getAddressType());
             }
         }
     }
@@ -191,7 +191,7 @@
 
             assertTrue(stringRepr + " expected to be a locally assigned address",
                     mac.isLocallyAssigned());
-            assertEquals(MacAddress.TYPE_UNICAST, mac.addressType());
+            assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
             assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
                     stringRepr.startsWith(expectedLocalOui));
         }
diff --git a/tests/net/java/android/net/NetworkTest.java b/tests/net/java/android/net/NetworkTest.java
index bacf986..94d01e9 100644
--- a/tests/net/java/android/net/NetworkTest.java
+++ b/tests/net/java/android/net/NetworkTest.java
@@ -147,9 +147,9 @@
 
         // Adjust as necessary to test an implementation's specific constants.
         // When running with runtest, "adb logcat -s TestRunner" can be useful.
-        assertEquals(4311403230L, one.getNetworkHandle());
-        assertEquals(8606370526L, two.getNetworkHandle());
-        assertEquals(12901337822L, three.getNetworkHandle());
+        assertEquals(7700664333L, one.getNetworkHandle());
+        assertEquals(11995631629L, two.getNetworkHandle());
+        assertEquals(16290598925L, three.getNetworkHandle());
     }
 
     private static <T> void assertNotEqual(T t1, T t2) {
diff --git a/core/tests/coretests/src/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
similarity index 100%
rename from core/tests/coretests/src/android/net/NetworkUtilsTest.java
rename to tests/net/java/android/net/NetworkUtilsTest.java
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/tests/net/java/android/net/RouteInfoTest.java
similarity index 100%
rename from core/tests/coretests/src/android/net/RouteInfoTest.java
rename to tests/net/java/android/net/RouteInfoTest.java
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 725ddb9..9b75a50 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -35,6 +35,7 @@
 import android.net.ip.IpManager;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.RaEvent;
+import android.net.util.InterfaceParams;
 import android.os.ConditionVariable;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -62,7 +63,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
-import java.net.NetworkInterface;
 import java.nio.ByteBuffer;
 import java.util.List;
 import java.util.Random;
@@ -635,7 +635,7 @@
 
         public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback,
                 IpConnectivityLog log) throws Exception {
-            super(config, NetworkInterface.getByName("lo"), ipManagerCallback, log);
+            super(config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
         }
 
         // Pretend an RA packet has been received and show it to ApfFilter.
diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
index 54776db..e65585f 100644
--- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
+++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.when;
 
+import android.net.util.InterfaceParams;
 import android.net.util.SharedLog;
 import android.os.Handler;
 import android.os.Looper;
@@ -54,8 +55,8 @@
     }
 
     IpReachabilityMonitor makeMonitor() {
-        return new IpReachabilityMonitor(
-                "fake0", 1, mHandler, mLog, mCallback, null, mDependencies);
+        final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null);
+        return new IpReachabilityMonitor(ifParams, mHandler, mLog, mCallback, null, mDependencies);
     }
 
     @Test
diff --git a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
index 38d3d74..f9b7ec8 100644
--- a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
+++ b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.net.MacAddress;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.test.filters.SmallTest;
 
@@ -36,9 +37,7 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class ConnectivityPacketSummaryTest {
-    private static final byte[] MYHWADDR = {
-        asByte(0x80), asByte(0x7a), asByte(0xbf), asByte(0x6f), asByte(0x48), asByte(0xf3)
-    };
+    private static final MacAddress MYHWADDR = MacAddress.fromString("80:7a:bf:6f:48:f3");
 
     private String getSummary(String hexBytes) {
         hexBytes = hexBytes.replaceAll("\\s+", "");
diff --git a/tests/net/java/android/net/util/InterfaceParamsTest.java b/tests/net/java/android/net/util/InterfaceParamsTest.java
new file mode 100644
index 0000000..21728af
--- /dev/null
+++ b/tests/net/java/android/net/util/InterfaceParamsTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class InterfaceParamsTest {
+    @Test
+    public void testNullInterfaceReturnsNull() {
+        assertNull(InterfaceParams.getByName(null));
+    }
+
+    @Test
+    public void testNonExistentInterfaceReturnsNull() {
+        assertNull(InterfaceParams.getByName("doesnotexist0"));
+    }
+
+    @Test
+    public void testLoopback() {
+        final InterfaceParams ifParams = InterfaceParams.getByName("lo");
+        assertNotNull(ifParams);
+        assertEquals("lo", ifParams.name);
+        assertTrue(ifParams.index > 0);
+        assertNotNull(ifParams.macAddr);
+        assertTrue(ifParams.defaultMtu >= NetworkConstants.ETHER_MTU);
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 113cd37..b8e37f3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -55,14 +55,20 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -116,6 +122,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
@@ -132,6 +139,7 @@
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
@@ -174,8 +182,11 @@
 
     @Mock IpConnectivityMetrics.Logger mMetricsService;
     @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
+    @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
 
+    private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class);
+
     // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
     // do not go through ConnectivityService but talk to netd directly, so they don't automatically
     // reflect the state of our test ConnectivityService.
@@ -872,7 +883,7 @@
         LocalServices.addService(
                 NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
         mService = new WrappedConnectivityService(mServiceContext,
-                mock(INetworkManagementService.class),
+                mNetworkManagementService,
                 mStatsService,
                 mock(INetworkPolicyManager.class),
                 mock(IpConnectivityLog.class));
@@ -1381,39 +1392,75 @@
             return null;
         }
 
-        void expectAvailableCallbacks(
-                MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
+        // Expects onAvailable and the callbacks that follow it. These are:
+        // - onSuspended, iff the network was suspended when the callbacks fire.
+        // - onCapabilitiesChanged.
+        // - onLinkPropertiesChanged.
+        //
+        // @param agent the network to expect the callbacks on.
+        // @param expectSuspended whether to expect a SUSPENDED callback.
+        // @param expectValidated the expected value of the VALIDATED capability in the
+        //        onCapabilitiesChanged callback.
+        // @param timeoutMs how long to wait for the callbacks.
+        void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended,
+                boolean expectValidated, int timeoutMs) {
             expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
             if (expectSuspended) {
                 expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
             }
-            expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
+            if (expectValidated) {
+                expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+            } else {
+                expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent);
+            }
             expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
         }
 
-        void expectAvailableCallbacks(MockNetworkAgent agent) {
-            expectAvailableCallbacks(agent, false, TIMEOUT_MS);
+        // Expects the available callbacks (validated), plus onSuspended.
+        void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent, boolean expectValidated) {
+            expectAvailableCallbacks(agent, true, expectValidated, TIMEOUT_MS);
         }
 
-        void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) {
-            expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+        void expectAvailableCallbacksValidated(MockNetworkAgent agent) {
+            expectAvailableCallbacks(agent, false, true, TIMEOUT_MS);
         }
 
-        void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
-            expectAvailableCallbacks(agent, false, TIMEOUT_MS);
+        void expectAvailableCallbacksUnvalidated(MockNetworkAgent agent) {
+            expectAvailableCallbacks(agent, false, false, TIMEOUT_MS);
+        }
+
+        // Expects the available callbacks (where the onCapabilitiesChanged must contain the
+        // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the
+        // one we just sent.
+        // TODO: this is likely a bug. Fix it and remove this method.
+        void expectAvailableDoubleValidatedCallbacks(MockNetworkAgent agent) {
+            expectCallback(CallbackState.AVAILABLE, agent, TIMEOUT_MS);
+            NetworkCapabilities nc1 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+            expectCallback(CallbackState.LINK_PROPERTIES, agent, TIMEOUT_MS);
+            NetworkCapabilities nc2 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+            assertEquals(nc1, nc2);
+        }
+
+        // Expects the available callbacks where the onCapabilitiesChanged must not have validated,
+        // then expects another onCapabilitiesChanged that has the validated bit set. This is used
+        // when a network connects and satisfies a callback, and then immediately validates.
+        void expectAvailableThenValidatedCallbacks(MockNetworkAgent agent) {
+            expectAvailableCallbacksUnvalidated(agent);
             expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
         }
 
-        void expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
+        NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
             CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
             NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
             assertTrue(nc.hasCapability(capability));
+            return nc;
         }
 
-        void expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
+        NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
             CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
             NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
             assertFalse(nc.hasCapability(capability));
+            return nc;
         }
 
         void assertNoCallback() {
@@ -1450,8 +1497,8 @@
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
-        genericNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
-        cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         waitFor(cv);
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1465,8 +1512,8 @@
         cv = waitForConnectivityBroadcasts(2);
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
-        genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
-        wifiNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         waitFor(cv);
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1489,8 +1536,8 @@
         // Test validated networks
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        genericNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
-        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
@@ -1502,10 +1549,10 @@
 
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-        wifiNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1541,32 +1588,32 @@
         mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
 
         mCellNetworkAgent.connect(true);
-        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.connect(true);
         // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
         // We then get LOSING when wifi validates and cell is outscored.
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mEthernetNetworkAgent.connect(true);
-        callback.expectAvailableCallbacks(mEthernetNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
         // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
+        defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
         assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mEthernetNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
 
         for (int i = 0; i < 4; i++) {
             MockNetworkAgent oldNetwork, newNetwork;
@@ -1583,7 +1630,7 @@
             callback.expectCallback(CallbackState.LOSING, oldNetwork);
             // TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
             // longer lingering?
-            defaultCallback.expectAvailableCallbacks(newNetwork);
+            defaultCallback.expectAvailableCallbacksValidated(newNetwork);
             assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
         }
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -1603,7 +1650,7 @@
         // Disconnect our test networks.
         mWiFiNetworkAgent.disconnect();
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         mCellNetworkAgent.disconnect();
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
 
@@ -1619,22 +1666,22 @@
 
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);   // Score: 10
-        callback.expectAvailableCallbacks(mCellNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi with a score of 20.
         // Cell stays up because it would satisfy the default request if it validated.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);   // Score: 20
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi with a score of 70.
@@ -1642,33 +1689,33 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.adjustScore(50);
         mWiFiNetworkAgent.connect(false);   // Score: 70
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Tear down wifi.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
         // it's arguably correct to linger it, since it was the default network before it validated.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         mCellNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1676,12 +1723,12 @@
         // If a network is lingering, and we add and remove a request from it, resume lingering.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
@@ -1700,7 +1747,7 @@
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
 
         // Cell is now the default network. Pin it with a cell-specific request.
         noopCallback = new NetworkCallback();  // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1709,8 +1756,8 @@
         // Now connect wifi, and expect it to become the default network.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         // The default request is lingering on cell, but nothing happens to cell, and we send no
         // callbacks for it, because it's kept up by cellRequest.
         callback.assertNoCallback();
@@ -1726,14 +1773,14 @@
         // Register a TRACK_DEFAULT request and check that it does not affect lingering.
         TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(trackDefaultCallback);
-        trackDefaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
         mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
         mEthernetNetworkAgent.connect(true);
-        callback.expectAvailableCallbacks(mEthernetNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
         callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
-        trackDefaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
+        trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
+        defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
 
         // Let linger run its course.
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
@@ -1760,13 +1807,13 @@
         // Bring up validated cell.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
 
         // Bring up unvalidated wifi with explicitlySelected=true.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(false);
         mWiFiNetworkAgent.connect(false);
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
 
         // Cell Remains the default.
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -1789,7 +1836,7 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(false);
         mWiFiNetworkAgent.connect(false);
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
 
         // If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
         // network to disconnect.
@@ -1800,7 +1847,7 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(false);
         mWiFiNetworkAgent.connect(true);
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -1809,7 +1856,7 @@
         // TODO: fix this.
         mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
         mEthernetNetworkAgent.connect(true);
-        callback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
+        callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
         assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         callback.assertNoCallback();
 
@@ -1982,7 +2029,7 @@
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mCellNetworkAgent.connectWithoutInternet();
-        networkCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         verifyActiveNetwork(TRANSPORT_WIFI);
 
         // Test releasing NetworkRequest disconnects cellular with MMS
@@ -2011,7 +2058,7 @@
         MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mmsNetworkAgent.connectWithoutInternet();
-        networkCallback.expectAvailableCallbacks(mmsNetworkAgent);
+        networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
 
         // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
@@ -2038,7 +2085,7 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         String firstRedirectUrl = "http://example.com/firstPath";
         mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
-        captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
 
         // Take down network.
@@ -2051,7 +2098,7 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         String secondRedirectUrl = "http://example.com/secondPath";
         mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
-        captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
 
         // Make captive portal disappear then revalidate.
@@ -2061,9 +2108,7 @@
         captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
         // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
-        validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
-        // TODO: Investigate only sending available callbacks.
-        validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
 
         // Break network connectivity.
         // Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -2087,7 +2132,7 @@
         // Bring up wifi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        validatedCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Check that calling startCaptivePortalApp does nothing.
@@ -2098,7 +2143,7 @@
         // Turn into a captive portal.
         mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 302;
         mCm.reportNetworkConnectivity(wifiNetwork, false);
-        captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
         // Check that startCaptivePortalApp sends the expected intent.
@@ -2111,7 +2156,7 @@
         mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
         CaptivePortal c = (CaptivePortal) intent.getExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
         c.reportCaptivePortalDismissed();
-        validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
         captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
         mCm.unregisterNetworkCallback(validatedCallback);
@@ -2154,7 +2199,7 @@
         mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
 
         // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
-        validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
         // But there should be no CaptivePortal callback.
         captivePortalCallback.assertNoCallback();
     }
@@ -2192,14 +2237,14 @@
 
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
-        cEmpty1.expectAvailableCallbacks(mWiFiNetworkAgent);
-        cEmpty2.expectAvailableCallbacks(mWiFiNetworkAgent);
-        cEmpty3.expectAvailableCallbacks(mWiFiNetworkAgent);
-        cEmpty4.expectAvailableCallbacks(mWiFiNetworkAgent);
+        cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        cEmpty3.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        cEmpty4.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertNoCallbacks(cFoo, cBar);
 
         mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("foo"));
-        cFoo.expectAvailableCallbacks(mWiFiNetworkAgent);
+        cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         for (TestNetworkCallback c: emptyCallbacks) {
             c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
         }
@@ -2208,7 +2253,7 @@
 
         mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("bar"));
         cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        cBar.expectAvailableCallbacks(mWiFiNetworkAgent);
+        cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         for (TestNetworkCallback c: emptyCallbacks) {
             c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
         }
@@ -2337,14 +2382,14 @@
         // Bring up cell and expect CALLBACK_AVAILABLE.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
-        defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
 
         // Bring up wifi and expect CALLBACK_AVAILABLE.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         cellNetworkCallback.assertNoCallback();
-        defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
 
         // Bring down cell. Expect no default network callback, since it wasn't the default.
         mCellNetworkAgent.disconnect();
@@ -2354,7 +2399,7 @@
         // Bring up cell. Expect no default network callback, since it won't be the default.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.assertNoCallback();
 
         // Bring down wifi. Expect the default network callback to notified of LOST wifi
@@ -2362,7 +2407,7 @@
         mWiFiNetworkAgent.disconnect();
         cellNetworkCallback.assertNoCallback();
         defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         mCellNetworkAgent.disconnect();
         cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -2383,7 +2428,7 @@
         // We should get onAvailable(), onCapabilitiesChanged(), and
         // onLinkPropertiesChanged() in rapid succession. Additionally, we
         // should get onCapabilitiesChanged() when the mobile network validates.
-        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
 
         // Update LinkProperties.
@@ -2404,7 +2449,7 @@
         mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
         // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
         // as well as onNetworkSuspended() in rapid succession.
-        dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent);
+        dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true);
         dfltNetworkCallback.assertNoCallback();
 
         mCm.unregisterNetworkCallback(dfltNetworkCallback);
@@ -2444,18 +2489,18 @@
 
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
-        fgCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
 
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
 
         // When wifi connects, cell lingers.
-        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-        fgCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
@@ -2479,8 +2524,8 @@
         // is currently delivered before the onAvailable() callbacks.
         // TODO: Fix this.
         cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
-        cellCallback.expectAvailableCallbacks(mCellNetworkAgent);
-        fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+        fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         // Expect a network capabilities update with FOREGROUND, because the most recent
         // request causes its state to change.
         callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
@@ -2500,7 +2545,7 @@
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
 
         mCm.unregisterNetworkCallback(callback);
@@ -2640,7 +2685,7 @@
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         testFactory.expectAddRequests(2);  // Because the cell request changes score twice.
         mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         testFactory.waitForNetworkRequests(2);
         assertFalse(testFactory.getMyStartRequested());  // Because the cell network outscores us.
 
@@ -2731,16 +2776,15 @@
         // Bring up validated cell.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         Network cellNetwork = mCellNetworkAgent.getNetwork();
 
         // Bring up validated wifi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
-        validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
-        validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+        validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi.
@@ -2761,18 +2805,18 @@
         // that we switch back to cell.
         tracker.configRestrictsAvoidBadWifi = false;
         tracker.reevaluate();
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
 
         // Switch back to a restrictive carrier.
         tracker.configRestrictsAvoidBadWifi = true;
         tracker.reevaluate();
-        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
 
         // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
         mCm.setAvoidUnvalidated(wifiNetwork);
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2783,9 +2827,8 @@
         mWiFiNetworkAgent.disconnect();
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
-        validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
-        validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+        validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi and expect the dialog to appear.
@@ -2799,7 +2842,7 @@
         tracker.reevaluate();
 
         // We now switch to cell.
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2810,17 +2853,17 @@
         // We switch to wifi and then to cell.
         Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
         tracker.reevaluate();
-        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
         Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
         tracker.reevaluate();
-        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
 
         // If cell goes down, we switch to wifi.
         mCellNetworkAgent.disconnect();
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
-        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         validatedWifiCallback.assertNoCallback();
 
         mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -2862,7 +2905,7 @@
 
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
-        networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, timeoutMs);
+        networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, timeoutMs);
 
         // pass timeout and validate that UNAVAILABLE is not called
         networkCallback.assertNoCallback();
@@ -2883,7 +2926,7 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         final int assertTimeoutMs = 100;
-        networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs);
+        networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, assertTimeoutMs);
         mWiFiNetworkAgent.disconnect();
         networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
@@ -3370,7 +3413,7 @@
 
         // Bring up wifi aware network.
         wifiAware.connect(false, false);
-        callback.expectAvailableCallbacks(wifiAware);
+        callback.expectAvailableCallbacksUnvalidated(wifiAware);
 
         assertNull(mCm.getActiveNetworkInfo());
         assertNull(mCm.getActiveNetwork());
@@ -3489,6 +3532,44 @@
         reset(mStatsService);
     }
 
+    @Test
+    public void testBasicDnsConfigurationPushed() throws Exception {
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        waitForIdle();
+        verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
+                anyInt(), any(), any(), any(), anyBoolean(), anyString());
+
+        final LinkProperties cellLp = new LinkProperties();
+        cellLp.setInterfaceName("test_rmnet_data0");
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        mCellNetworkAgent.connect(false);
+        waitForIdle();
+        verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
+                anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString());
+        // CS tells netd about the empty DNS config for this network.
+        assertEmpty(mStringArrayCaptor.getValue());
+        reset(mNetworkManagementService);
+
+        cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        waitForIdle();
+        verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
+                anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString());
+        assertEquals(1, mStringArrayCaptor.getValue().length);
+        assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
+        reset(mNetworkManagementService);
+
+        cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        waitForIdle();
+        verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
+                anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString());
+        assertEquals(2, mStringArrayCaptor.getValue().length);
+        assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
+                new String[]{"2001:db8::1", "192.0.2.1"}));
+        reset(mNetworkManagementService);
+    }
+
     private void checkDirectlyConnectedRoutes(Object callbackObj,
             Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
         assertTrue(callbackObj instanceof LinkProperties);
diff --git a/tests/testables/src/android/testing/PollingCheck.java b/tests/testables/src/android/testing/PollingCheck.java
new file mode 100644
index 0000000..5a31450
--- /dev/null
+++ b/tests/testables/src/android/testing/PollingCheck.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.testing;
+
+import junit.framework.Assert;
+import java.util.concurrent.Callable;
+
+public abstract class PollingCheck {
+    private static final long TIME_SLICE = 50;
+    private long mTimeout = 3000;
+
+    public static interface PollingCheckCondition {
+        boolean canProceed();
+    }
+
+    public PollingCheck() {
+    }
+
+    public PollingCheck(long timeout) {
+        mTimeout = timeout;
+    }
+
+    protected abstract boolean check();
+
+    public void run() {
+        if (check()) {
+            return;
+        }
+
+        long timeout = mTimeout;
+        while (timeout > 0) {
+            try {
+                Thread.sleep(TIME_SLICE);
+            } catch (InterruptedException e) {
+                Assert.fail("unexpected InterruptedException");
+            }
+
+            if (check()) {
+                return;
+            }
+
+            timeout -= TIME_SLICE;
+        }
+
+        Assert.fail("unexpected timeout");
+    }
+
+    public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
+            throws Exception {
+        while (timeout > 0) {
+            if (condition.call()) {
+                return;
+            }
+
+            Thread.sleep(TIME_SLICE);
+            timeout -= TIME_SLICE;
+        }
+
+        Assert.fail(message.toString());
+    }
+
+    public static void waitFor(final PollingCheckCondition condition) {
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+        }.run();
+    }
+
+    public static void waitFor(long timeout, final PollingCheckCondition condition) {
+        new PollingCheck(timeout) {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+        }.run();
+    }
+}
+
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index 6d2257f..81bcecc 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -42,6 +42,8 @@
 // Info about an APK loaded in memory.
 class LoadedApk {
  public:
+  virtual ~LoadedApk() = default;
+
   // Loads both binary and proto APKs from disk.
   static std::unique_ptr<LoadedApk> LoadApkFromPath(const ::android::StringPiece& path,
                                                     IDiagnostics* diag);
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 24b28dd..7cffeea 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -17,6 +17,7 @@
 #include "ResourceParser.h"
 
 #include <functional>
+#include <limits>
 #include <sstream>
 
 #include "android-base/logging.h"
@@ -987,8 +988,7 @@
     type_mask = ParseFormatAttribute(maybe_format.value());
     if (type_mask == 0) {
       diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
-                   << "invalid attribute format '" << maybe_format.value()
-                   << "'");
+                   << "invalid attribute format '" << maybe_format.value() << "'");
       return false;
     }
   }
@@ -1000,8 +1000,7 @@
     if (!min_str.empty()) {
       std::u16string min_str16 = util::Utf8ToUtf16(min_str);
       android::Res_value value;
-      if (android::ResTable::stringToInt(min_str16.data(), min_str16.size(),
-                                         &value)) {
+      if (android::ResTable::stringToInt(min_str16.data(), min_str16.size(), &value)) {
         maybe_min = static_cast<int32_t>(value.data);
       }
     }
@@ -1018,8 +1017,7 @@
     if (!max_str.empty()) {
       std::u16string max_str16 = util::Utf8ToUtf16(max_str);
       android::Res_value value;
-      if (android::ResTable::stringToInt(max_str16.data(), max_str16.size(),
-                                         &value)) {
+      if (android::ResTable::stringToInt(max_str16.data(), max_str16.size(), &value)) {
         maybe_max = static_cast<int32_t>(value.data);
       }
     }
@@ -1061,8 +1059,7 @@
     const Source item_source = source_.WithLine(parser->line_number());
     const std::string& element_namespace = parser->element_namespace();
     const std::string& element_name = parser->element_name();
-    if (element_namespace.empty() &&
-        (element_name == "flag" || element_name == "enum")) {
+    if (element_namespace.empty() && (element_name == "flag" || element_name == "enum")) {
       if (element_name == "enum") {
         if (type_mask & android::ResTable_map::TYPE_FLAGS) {
           diag_->Error(DiagMessage(item_source)
@@ -1120,17 +1117,12 @@
     return false;
   }
 
-  std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(weak);
+  std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(
+      type_mask ? type_mask : uint32_t{android::ResTable_map::TYPE_ANY});
+  attr->SetWeak(weak);
   attr->symbols = std::vector<Attribute::Symbol>(items.begin(), items.end());
-  attr->type_mask =
-      type_mask ? type_mask : uint32_t(android::ResTable_map::TYPE_ANY);
-  if (maybe_min) {
-    attr->min_int = maybe_min.value();
-  }
-
-  if (maybe_max) {
-    attr->max_int = maybe_max.value();
-  }
+  attr->min_int = maybe_min.value_or_default(std::numeric_limits<int32_t>::min());
+  attr->max_int = maybe_max.value_or_default(std::numeric_limits<int32_t>::max());
   out_resource->value = std::move(attr);
   return true;
 }
@@ -1445,11 +1437,9 @@
     const std::string& element_namespace = parser->element_namespace();
     const std::string& element_name = parser->element_name();
     if (element_namespace.empty() && element_name == "attr") {
-      Maybe<StringPiece> maybe_name =
-          xml::FindNonEmptyAttribute(parser, "name");
+      Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
       if (!maybe_name) {
-        diag_->Error(DiagMessage(item_source)
-                     << "<attr> tag must have a 'name' attribute");
+        diag_->Error(DiagMessage(item_source) << "<attr> tag must have a 'name' attribute");
         error = true;
         continue;
       }
@@ -1457,8 +1447,7 @@
       // If this is a declaration, the package name may be in the name. Separate
       // these out.
       // Eg. <attr name="android:text" />
-      Maybe<Reference> maybe_ref =
-          ResourceUtils::ParseXmlAttributeName(maybe_name.value());
+      Maybe<Reference> maybe_ref = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
       if (!maybe_ref) {
         diag_->Error(DiagMessage(item_source) << "<attr> tag has invalid name '"
                                               << maybe_name.value() << "'");
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 3172892..9905f82 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -262,9 +262,8 @@
   // attributes all-over, we do special handling to see
   // which definition sticks.
   //
-  if (existing_attr->type_mask == incoming_attr->type_mask) {
-    // The two attributes are both DECLs, but they are plain attributes
-    // with the same formats.
+  if (existing_attr->IsCompatibleWith(*incoming_attr)) {
+    // The two attributes are both DECLs, but they are plain attributes with compatible formats.
     // Keep the strongest one.
     return existing_attr->IsWeak() ? CollisionResult::kTakeNew : CollisionResult::kKeepOriginal;
   }
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index eaa2d0b..95e30c4 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -81,10 +81,7 @@
   DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
 };
 
-/**
- * Represents a resource entry, which may have
- * varying values for each defined configuration.
- */
+// Represents a resource entry, which may have varying values for each defined configuration.
 class ResourceEntry {
  public:
   // The name of the resource. Immutable, as this determines the order of this resource
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index eb75f94..7fa8ea2 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -102,23 +102,37 @@
 TEST(ResourceTableTest, OverrideWeakResourceValue) {
   ResourceTable table;
 
-  ASSERT_TRUE(table.AddResource(
-      test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
-      util::make_unique<Attribute>(true), test::GetDiagnostics()));
+  ASSERT_TRUE(table.AddResource(test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
+                                test::AttributeBuilder().SetWeak(true).Build(),
+                                test::GetDiagnostics()));
 
   Attribute* attr = test::GetValue<Attribute>(&table, "android:attr/foo");
   ASSERT_THAT(attr, NotNull());
   EXPECT_TRUE(attr->IsWeak());
 
-  ASSERT_TRUE(table.AddResource(
-      test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
-      util::make_unique<Attribute>(false), test::GetDiagnostics()));
+  ASSERT_TRUE(table.AddResource(test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
+                                util::make_unique<Attribute>(), test::GetDiagnostics()));
 
   attr = test::GetValue<Attribute>(&table, "android:attr/foo");
   ASSERT_THAT(attr, NotNull());
   EXPECT_FALSE(attr->IsWeak());
 }
 
+TEST(ResourceTableTest, AllowCompatibleDuplicateAttributes) {
+  ResourceTable table;
+
+  const ResourceName name = test::ParseNameOrDie("android:attr/foo");
+  Attribute attr_one(android::ResTable_map::TYPE_STRING);
+  attr_one.SetWeak(true);
+  Attribute attr_two(android::ResTable_map::TYPE_STRING | android::ResTable_map::TYPE_REFERENCE);
+  attr_two.SetWeak(true);
+
+  ASSERT_TRUE(table.AddResource(name, ConfigDescription{}, "",
+                                util::make_unique<Attribute>(attr_one), test::GetDiagnostics()));
+  ASSERT_TRUE(table.AddResource(name, ConfigDescription{}, "",
+                                util::make_unique<Attribute>(attr_two), test::GetDiagnostics()));
+}
+
 TEST(ResourceTableTest, ProductVaryingValues) {
   ResourceTable table;
 
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index e637c3e..cb786d3 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -179,12 +179,11 @@
 }
 
 TEST(ResourceUtilsTest, ParseEmptyFlag) {
-  std::unique_ptr<Attribute> attr =
-      test::AttributeBuilder(false)
-          .SetTypeMask(ResTable_map::TYPE_FLAGS)
-          .AddItem("one", 0x01)
-          .AddItem("two", 0x02)
-          .Build();
+  std::unique_ptr<Attribute> attr = test::AttributeBuilder()
+                                        .SetTypeMask(ResTable_map::TYPE_FLAGS)
+                                        .AddItem("one", 0x01)
+                                        .AddItem("two", 0x02)
+                                        .Build();
 
   std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseFlagSymbol(attr.get(), "");
   ASSERT_THAT(result, NotNull());
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index a782cd3..77cee06 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -507,17 +507,10 @@
   }
 }
 
-Attribute::Attribute()
-    : type_mask(0u),
-      min_int(std::numeric_limits<int32_t>::min()),
-      max_int(std::numeric_limits<int32_t>::max()) {
-}
-
-Attribute::Attribute(bool w, uint32_t t)
+Attribute::Attribute(uint32_t t)
     : type_mask(t),
       min_int(std::numeric_limits<int32_t>::min()),
       max_int(std::numeric_limits<int32_t>::max()) {
-  weak_ = w;
 }
 
 std::ostream& operator<<(std::ostream& out, const Attribute::Symbol& s) {
@@ -568,6 +561,20 @@
                     });
 }
 
+bool Attribute::IsCompatibleWith(const Attribute& attr) const {
+  // If the high bits are set on any of these attribute type masks, then they are incompatible.
+  // We don't check that flags and enums are identical.
+  if ((type_mask & ~android::ResTable_map::TYPE_ANY) != 0 ||
+      (attr.type_mask & ~android::ResTable_map::TYPE_ANY) != 0) {
+    return false;
+  }
+
+  // Every attribute accepts a reference.
+  uint32_t this_type_mask = type_mask | android::ResTable_map::TYPE_REFERENCE;
+  uint32_t that_type_mask = attr.type_mask | android::ResTable_map::TYPE_REFERENCE;
+  return this_type_mask == that_type_mask;
+}
+
 Attribute* Attribute::Clone(StringPool* /*new_pool*/) const {
   return new Attribute(*this);
 }
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index b2ec8bdd..6371c4c 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -300,10 +300,15 @@
   int32_t max_int;
   std::vector<Symbol> symbols;
 
-  Attribute();
-  explicit Attribute(bool w, uint32_t t = 0u);
+  explicit Attribute(uint32_t t = 0u);
 
   bool Equals(const Value* value) const override;
+
+  // Returns true if this Attribute's format is compatible with the given Attribute. The basic
+  // rule is that TYPE_REFERENCE can be ignored for both of the Attributes, and TYPE_FLAGS and
+  // TYPE_ENUMS are never compatible.
+  bool IsCompatibleWith(const Attribute& attr) const;
+
   Attribute* Clone(StringPool* new_pool) const override;
   std::string MaskString() const;
   void Print(std::ostream* out) const override;
diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp
index a80a9dc..c4a1108 100644
--- a/tools/aapt2/ResourceValues_test.cpp
+++ b/tools/aapt2/ResourceValues_test.cpp
@@ -24,6 +24,18 @@
 
 namespace aapt {
 
+namespace {
+
+// Attribute types.
+constexpr const uint32_t TYPE_DIMENSION = android::ResTable_map::TYPE_DIMENSION;
+constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM;
+constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS;
+constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER;
+constexpr const uint32_t TYPE_REFERENCE = android::Res_value::TYPE_REFERENCE;
+constexpr const uint32_t TYPE_STRING = android::ResTable_map::TYPE_STRING;
+
+}  // namespace
+
 TEST(ResourceValuesTest, PluralEquals) {
   StringPool pool;
 
@@ -206,23 +218,19 @@
   android::Res_value value = {};
   ASSERT_TRUE(Reference().Flatten(&value));
 
-  EXPECT_EQ(android::Res_value::TYPE_REFERENCE, value.dataType);
-  EXPECT_EQ(0x0u, value.data);
+  EXPECT_THAT(value.dataType, Eq(android::Res_value::TYPE_REFERENCE));
+  EXPECT_THAT(value.data, Eq(0u));
 }
 
 TEST(ResourcesValuesTest, AttributeMatches) {
-  constexpr const uint32_t TYPE_DIMENSION = android::ResTable_map::TYPE_DIMENSION;
-  constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM;
-  constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS;
-  constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER;
   constexpr const uint8_t TYPE_INT_DEC = android::Res_value::TYPE_INT_DEC;
 
-  Attribute attr1(false /*weak*/, TYPE_DIMENSION);
+  Attribute attr1(TYPE_DIMENSION);
   EXPECT_FALSE(attr1.Matches(*ResourceUtils::TryParseColor("#7fff00")));
   EXPECT_TRUE(attr1.Matches(*ResourceUtils::TryParseFloat("23dp")));
   EXPECT_TRUE(attr1.Matches(*ResourceUtils::TryParseReference("@android:string/foo")));
 
-  Attribute attr2(false /*weak*/, TYPE_INTEGER | TYPE_ENUM);
+  Attribute attr2(TYPE_INTEGER | TYPE_ENUM);
   attr2.min_int = 0;
   attr2.symbols.push_back(Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")),
                                             static_cast<uint32_t>(-1)});
@@ -231,7 +239,7 @@
   EXPECT_TRUE(attr2.Matches(BinaryPrimitive(TYPE_INT_DEC, 1u)));
   EXPECT_FALSE(attr2.Matches(BinaryPrimitive(TYPE_INT_DEC, static_cast<uint32_t>(-2))));
 
-  Attribute attr3(false /*weak*/, TYPE_INTEGER | TYPE_FLAGS);
+  Attribute attr3(TYPE_INTEGER | TYPE_FLAGS);
   attr3.max_int = 100;
   attr3.symbols.push_back(
       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
@@ -251,11 +259,33 @@
   // Not a flag and greater than max_int.
   EXPECT_FALSE(attr3.Matches(BinaryPrimitive(TYPE_INT_DEC, 127u)));
 
-  Attribute attr4(false /*weak*/, TYPE_ENUM);
+  Attribute attr4(TYPE_ENUM);
   attr4.symbols.push_back(
       Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u});
   EXPECT_TRUE(attr4.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x01u)));
   EXPECT_FALSE(attr4.Matches(BinaryPrimitive(TYPE_INT_DEC, 0x02u)));
 }
 
+TEST(ResourcesValuesTest, AttributeIsCompatible) {
+  Attribute attr_one(TYPE_STRING | TYPE_REFERENCE);
+  Attribute attr_two(TYPE_STRING);
+  Attribute attr_three(TYPE_ENUM);
+  Attribute attr_four(TYPE_REFERENCE);
+
+  EXPECT_TRUE(attr_one.IsCompatibleWith(attr_one));
+  EXPECT_TRUE(attr_one.IsCompatibleWith(attr_two));
+  EXPECT_FALSE(attr_one.IsCompatibleWith(attr_three));
+  EXPECT_FALSE(attr_one.IsCompatibleWith(attr_four));
+
+  EXPECT_TRUE(attr_two.IsCompatibleWith(attr_one));
+  EXPECT_TRUE(attr_two.IsCompatibleWith(attr_two));
+  EXPECT_FALSE(attr_two.IsCompatibleWith(attr_three));
+  EXPECT_FALSE(attr_two.IsCompatibleWith(attr_four));
+
+  EXPECT_FALSE(attr_three.IsCompatibleWith(attr_one));
+  EXPECT_FALSE(attr_three.IsCompatibleWith(attr_two));
+  EXPECT_FALSE(attr_three.IsCompatibleWith(attr_three));
+  EXPECT_FALSE(attr_three.IsCompatibleWith(attr_four));
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 3bec082..101f74e 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -772,8 +772,8 @@
       if (*type != ResourceType::kRaw) {
         if (path_data.extension == "xml") {
           compile_func = &CompileXml;
-        } else if (!options.no_png_crunch &&
-                   (path_data.extension == "png" || path_data.extension == "9.png")) {
+        } else if ((!options.no_png_crunch && path_data.extension == "png") ||
+                   path_data.extension == "9.png") {
           compile_func = &CompilePng;
         }
       }
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 72e07dc..c9e272c 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -388,10 +388,8 @@
   // generated from the attribute definitions themselves (b/62028956).
   if (const SymbolTable::Symbol* s = symm->FindById(R::attr::paddingHorizontal)) {
     std::vector<ReplacementAttr> replacements{
-        {"paddingLeft", R::attr::paddingLeft,
-         Attribute(false, android::ResTable_map::TYPE_DIMENSION)},
-        {"paddingRight", R::attr::paddingRight,
-         Attribute(false, android::ResTable_map::TYPE_DIMENSION)},
+        {"paddingLeft", R::attr::paddingLeft, Attribute(android::ResTable_map::TYPE_DIMENSION)},
+        {"paddingRight", R::attr::paddingRight, Attribute(android::ResTable_map::TYPE_DIMENSION)},
     };
     rules_[R::attr::paddingHorizontal] =
         util::make_unique<DegradeToManyRule>(std::move(replacements));
@@ -399,10 +397,8 @@
 
   if (const SymbolTable::Symbol* s = symm->FindById(R::attr::paddingVertical)) {
     std::vector<ReplacementAttr> replacements{
-        {"paddingTop", R::attr::paddingTop,
-         Attribute(false, android::ResTable_map::TYPE_DIMENSION)},
-        {"paddingBottom", R::attr::paddingBottom,
-         Attribute(false, android::ResTable_map::TYPE_DIMENSION)},
+        {"paddingTop", R::attr::paddingTop, Attribute(android::ResTable_map::TYPE_DIMENSION)},
+        {"paddingBottom", R::attr::paddingBottom, Attribute(android::ResTable_map::TYPE_DIMENSION)},
     };
     rules_[R::attr::paddingVertical] =
         util::make_unique<DegradeToManyRule>(std::move(replacements));
@@ -411,9 +407,9 @@
   if (const SymbolTable::Symbol* s = symm->FindById(R::attr::layout_marginHorizontal)) {
     std::vector<ReplacementAttr> replacements{
         {"layout_marginLeft", R::attr::layout_marginLeft,
-         Attribute(false, android::ResTable_map::TYPE_DIMENSION)},
+         Attribute(android::ResTable_map::TYPE_DIMENSION)},
         {"layout_marginRight", R::attr::layout_marginRight,
-         Attribute(false, android::ResTable_map::TYPE_DIMENSION)},
+         Attribute(android::ResTable_map::TYPE_DIMENSION)},
     };
     rules_[R::attr::layout_marginHorizontal] =
         util::make_unique<DegradeToManyRule>(std::move(replacements));
@@ -422,9 +418,9 @@
   if (const SymbolTable::Symbol* s = symm->FindById(R::attr::layout_marginVertical)) {
     std::vector<ReplacementAttr> replacements{
         {"layout_marginTop", R::attr::layout_marginTop,
-         Attribute(false, android::ResTable_map::TYPE_DIMENSION)},
+         Attribute(android::ResTable_map::TYPE_DIMENSION)},
         {"layout_marginBottom", R::attr::layout_marginBottom,
-         Attribute(false, android::ResTable_map::TYPE_DIMENSION)},
+         Attribute(android::ResTable_map::TYPE_DIMENSION)},
     };
     rules_[R::attr::layout_marginVertical] =
         util::make_unique<DegradeToManyRule>(std::move(replacements));
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 8d079ff..8215ddf 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -504,8 +504,8 @@
 std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef& name,
                                                            const ConfigDescription& config,
                                                            const ResTable_map_entry* map) {
-  const bool is_weak = (util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
-  std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak);
+  std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
+  attr->SetWeak((util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0);
 
   // First we must discover what type of attribute this is. Find the type mask.
   auto type_mask_iter = std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 51ccdc7..bab7010 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -215,7 +215,7 @@
 }
 
 TEST_F(TableFlattenerTest, FlattenMinMaxAttributes) {
-  Attribute attr(false);
+  Attribute attr;
   attr.type_mask = android::ResTable_map::TYPE_INTEGER;
   attr.min_int = 10;
   attr.max_int = 23;
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 3d6975d..d8635a9 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -635,8 +635,7 @@
     switch (pb_compound_value.value_case()) {
       case pb::CompoundValue::kAttr: {
         const pb::Attribute& pb_attr = pb_compound_value.attr();
-        std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
-        attr->type_mask = pb_attr.format_flags();
+        std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(pb_attr.format_flags());
         attr->min_int = pb_attr.min_int();
         attr->max_int = pb_attr.max_int();
         for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) {
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index d7f83fd..ccba5c6 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -180,7 +180,7 @@
   attr.name = "name";
   attr.namespace_uri = xml::kSchemaAndroid;
   attr.value = "23dp";
-  attr.compiled_attribute = xml::AaptAttribute({}, ResourceId(0x01010000));
+  attr.compiled_attribute = xml::AaptAttribute(Attribute{}, ResourceId(0x01010000));
   attr.compiled_value =
       ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
   attr.compiled_value->SetSource(Source().WithLine(25));
diff --git a/tools/aapt2/integration-tests/BasicTest/Android.mk b/tools/aapt2/integration-tests/BasicTest/Android.mk
new file mode 100644
index 0000000..6d2aac6
--- /dev/null
+++ b/tools/aapt2/integration-tests/BasicTest/Android.mk
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_PACKAGE_NAME := AaptBasicTest
+LOCAL_MODULE_TAGS := tests
+include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/integration-tests/BasicTest/AndroidManifest.xml b/tools/aapt2/integration-tests/BasicTest/AndroidManifest.xml
new file mode 100644
index 0000000..3743c40
--- /dev/null
+++ b/tools/aapt2/integration-tests/BasicTest/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.aapt.basic">
+
+    <uses-sdk android:minSdkVersion="21" />
+</manifest>
diff --git a/tools/aapt2/integration-tests/BasicTest/res/values/values.xml b/tools/aapt2/integration-tests/BasicTest/res/values/values.xml
new file mode 100644
index 0000000..8d6bb43
--- /dev/null
+++ b/tools/aapt2/integration-tests/BasicTest/res/values/values.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.
+-->
+
+<resources>
+    <declare-styleable name="AttrConflictStyleableOne">
+        <attr name="format_conflict" format="string|reference" />
+    </declare-styleable>
+
+    <declare-styleable name="AttrConflictStyleableTwo">
+        <attr name="format_conflict" format="string" />
+    </declare-styleable>
+</resources>
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 5beb594..e449546 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -57,7 +57,7 @@
           .SetPackageId("android", 0x01)
           .AddSimple("android:id/hey-man", ResourceId(0x01020000))
           .AddValue("android:attr/cool.attr", ResourceId(0x01010000),
-                    test::AttributeBuilder(false).Build())
+                    test::AttributeBuilder().Build())
           .AddValue("android:styleable/hey.dude", ResourceId(0x01030000),
                     test::StyleableBuilder()
                         .AddItem("android:attr/cool.attr", ResourceId(0x01010000))
@@ -229,10 +229,8 @@
       test::ResourceTableBuilder()
           .SetPackageId("android", 0x01)
           .SetPackageId("com.lib", 0x02)
-          .AddValue("android:attr/bar", ResourceId(0x01010000),
-                    test::AttributeBuilder(false).Build())
-          .AddValue("com.lib:attr/bar", ResourceId(0x02010000),
-                    test::AttributeBuilder(false).Build())
+          .AddValue("android:attr/bar", ResourceId(0x01010000), test::AttributeBuilder().Build())
+          .AddValue("com.lib:attr/bar", ResourceId(0x02010000), test::AttributeBuilder().Build())
           .AddValue("android:styleable/foo", ResourceId(0x01030000),
                     test::StyleableBuilder()
                         .AddItem("android:attr/bar", ResourceId(0x01010000))
@@ -290,7 +288,7 @@
 TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {}
 
 TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
-  Attribute attr(false);
+  Attribute attr;
   attr.SetComment(StringPiece("This is an attribute"));
 
   Styleable styleable;
@@ -375,7 +373,7 @@
 }
 
 TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
-  Attribute attr(false);
+  Attribute attr;
   attr.SetComment(StringPiece("removed"));
 
   std::unique_ptr<ResourceTable> table =
@@ -413,7 +411,7 @@
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
           .SetPackageId("android", 0x00)
-          .AddValue("android:attr/foo", ResourceId(0x00010000), util::make_unique<Attribute>(false))
+          .AddValue("android:attr/foo", ResourceId(0x00010000), util::make_unique<Attribute>())
           .AddValue("android:id/foo", ResourceId(0x00020000), util::make_unique<Id>())
           .AddValue(
               "android:style/foo", ResourceId(0x00030000),
diff --git a/tools/aapt2/link/XmlCompatVersioner_test.cpp b/tools/aapt2/link/XmlCompatVersioner_test.cpp
index 29ad25f..1ed4536 100644
--- a/tools/aapt2/link/XmlCompatVersioner_test.cpp
+++ b/tools/aapt2/link/XmlCompatVersioner_test.cpp
@@ -54,17 +54,17 @@
             .AddSymbolSource(
                 test::StaticSymbolSourceBuilder()
                     .AddPublicSymbol("android:attr/paddingLeft", R::attr::paddingLeft,
-                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
+                                     util::make_unique<Attribute>(TYPE_DIMENSION))
                     .AddPublicSymbol("android:attr/paddingRight", R::attr::paddingRight,
-                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
+                                     util::make_unique<Attribute>(TYPE_DIMENSION))
                     .AddPublicSymbol("android:attr/progressBarPadding", R::attr::progressBarPadding,
-                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
+                                     util::make_unique<Attribute>(TYPE_DIMENSION))
                     .AddPublicSymbol("android:attr/paddingStart", R::attr::paddingStart,
-                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
+                                     util::make_unique<Attribute>(TYPE_DIMENSION))
                     .AddPublicSymbol("android:attr/paddingHorizontal", R::attr::paddingHorizontal,
-                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
+                                     util::make_unique<Attribute>(TYPE_DIMENSION))
                     .AddSymbol("com.app:attr/foo", ResourceId(0x7f010000),
-                               util::make_unique<Attribute>(false, TYPE_STRING))
+                               util::make_unique<Attribute>(TYPE_STRING))
                     .Build())
             .Build();
   }
@@ -126,9 +126,8 @@
   XmlCompatVersioner::Rules rules;
   rules[R::attr::paddingHorizontal] =
       util::make_unique<DegradeToManyRule>(std::vector<ReplacementAttr>(
-          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(false, TYPE_DIMENSION)},
-           ReplacementAttr{"paddingRight", R::attr::paddingRight,
-                           Attribute(false, TYPE_DIMENSION)}}));
+          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(TYPE_DIMENSION)},
+           ReplacementAttr{"paddingRight", R::attr::paddingRight, Attribute(TYPE_DIMENSION)}}));
 
   const util::Range<ApiVersion> api_range{SDK_GINGERBREAD, SDK_O + 1};
 
@@ -187,12 +186,11 @@
   XmlCompatVersioner::Rules rules;
   rules[R::attr::progressBarPadding] =
       util::make_unique<DegradeToManyRule>(std::vector<ReplacementAttr>(
-          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(false, TYPE_DIMENSION)},
-           ReplacementAttr{"paddingRight", R::attr::paddingRight,
-                           Attribute(false, TYPE_DIMENSION)}}));
+          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(TYPE_DIMENSION)},
+           ReplacementAttr{"paddingRight", R::attr::paddingRight, Attribute(TYPE_DIMENSION)}}));
   rules[R::attr::paddingHorizontal] =
       util::make_unique<DegradeToManyRule>(std::vector<ReplacementAttr>({ReplacementAttr{
-          "progressBarPadding", R::attr::progressBarPadding, Attribute(false, TYPE_DIMENSION)}}));
+          "progressBarPadding", R::attr::progressBarPadding, Attribute(TYPE_DIMENSION)}}));
 
   const util::Range<ApiVersion> api_range{SDK_GINGERBREAD, SDK_O + 1};
 
@@ -267,9 +265,8 @@
   XmlCompatVersioner::Rules rules;
   rules[R::attr::paddingHorizontal] =
       util::make_unique<DegradeToManyRule>(std::vector<ReplacementAttr>(
-          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(false, TYPE_DIMENSION)},
-           ReplacementAttr{"paddingRight", R::attr::paddingRight,
-                           Attribute(false, TYPE_DIMENSION)}}));
+          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(TYPE_DIMENSION)},
+           ReplacementAttr{"paddingRight", R::attr::paddingRight, Attribute(TYPE_DIMENSION)}}));
 
   const util::Range<ApiVersion> api_range{SDK_GINGERBREAD, SDK_O + 1};
 
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index 8852c8e..160ff92 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -79,16 +79,15 @@
 
   void Visit(xml::Element* el) override {
     // The default Attribute allows everything except enums or flags.
-    constexpr const static uint32_t kDefaultTypeMask =
-        0xffffffffu & ~(android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS);
-    const static Attribute kDefaultAttribute(true /* weak */, kDefaultTypeMask);
+    Attribute default_attribute(android::ResTable_map::TYPE_ANY);
+    default_attribute.SetWeak(true);
 
     const Source source = source_.WithLine(el->line_number);
     for (xml::Attribute& attr : el->attributes) {
       // If the attribute has no namespace, interpret values as if
       // they were assigned to the default Attribute.
 
-      const Attribute* attribute = &kDefaultAttribute;
+      const Attribute* attribute = &default_attribute;
 
       if (Maybe<xml::ExtractedPackage> maybe_package =
               xml::ExtractPackageFromNamespace(attr.namespace_uri)) {
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 3cae0e8..2e97a2f 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -243,7 +243,7 @@
   // Check to see if it is an attribute.
   for (size_t i = 0; i < (size_t)count; i++) {
     if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
-      s->attribute = std::make_shared<Attribute>(false, entry[i].map.value.data);
+      s->attribute = std::make_shared<Attribute>(entry[i].map.value.data);
       break;
     }
   }
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index 495a48a..c4eab12 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -156,8 +156,8 @@
   return util::make_unique<BinaryPrimitive>(value);
 }
 
-AttributeBuilder::AttributeBuilder(bool weak) : attr_(util::make_unique<Attribute>(weak)) {
-  attr_->type_mask = android::ResTable_map::TYPE_ANY;
+AttributeBuilder::AttributeBuilder()
+    : attr_(util::make_unique<Attribute>(android::ResTable_map::TYPE_ANY)) {
 }
 
 AttributeBuilder& AttributeBuilder::SetTypeMask(uint32_t typeMask) {
@@ -165,6 +165,11 @@
   return *this;
 }
 
+AttributeBuilder& AttributeBuilder::SetWeak(bool weak) {
+  attr_->SetWeak(weak);
+  return *this;
+}
+
 AttributeBuilder& AttributeBuilder::AddItem(const StringPiece& name, uint32_t value) {
   attr_->symbols.push_back(
       Attribute::Symbol{Reference(ResourceName({}, ResourceType::kId, name)), value});
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 0d7451b..fd5262a 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -113,8 +113,9 @@
 
 class AttributeBuilder {
  public:
-  explicit AttributeBuilder(bool weak = false);
+  AttributeBuilder();
   AttributeBuilder& SetTypeMask(uint32_t typeMask);
+  AttributeBuilder& SetWeak(bool weak);
   AttributeBuilder& AddItem(const android::StringPiece& name, uint32_t value);
   std::unique_ptr<Attribute> Build();
 
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 421e545..399b0c6 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -100,9 +100,11 @@
         self.typ = raw[0]
         self.name = raw[1]
         self.args = []
+        self.throws = []
+        target = self.args
         for r in raw[2:]:
-            if r == "throws": break
-            self.args.append(r)
+            if r == "throws": target = self.throws
+            else: target.append(r)
 
         # identity for compat purposes
         ident = self.raw
@@ -391,7 +393,7 @@
                         prefix = clazz.pkg.name + ".action"
                     expected = prefix + "." + f.name[7:]
                     if f.value != expected:
-                        error(clazz, f, "C4", "Inconsistent action value; expected %s" % (expected))
+                        error(clazz, f, "C4", "Inconsistent action value; expected '%s'" % (expected))
 
 
 def verify_extras(clazz):
@@ -421,7 +423,7 @@
                         prefix = clazz.pkg.name + ".extra"
                     expected = prefix + "." + f.name[6:]
                     if f.value != expected:
-                        error(clazz, f, "C4", "Inconsistent extra value; expected %s" % (expected))
+                        error(clazz, f, "C4", "Inconsistent extra value; expected '%s'" % (expected))
 
 
 def verify_equals(clazz):
@@ -450,6 +452,10 @@
             (" final deprecated class " not in clazz.raw)):
             error(clazz, None, "FW8", "Parcelable classes must be final")
 
+        for c in clazz.ctors:
+            if c.args == ["android.os.Parcel"]:
+                error(clazz, c, "FW3", "Parcelable inflation is exposed through CREATOR, not raw constructors")
+
 
 def verify_protected(clazz):
     """Verify that no protected methods or fields are allowed."""
@@ -572,7 +578,7 @@
             if f.name == "SERVICE_INTERFACE":
                 found = True
                 if f.value != clazz.fullname:
-                    error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname))
+                    error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname))
 
     if "extends android.content.ContentProvider" in clazz.raw:
         test_methods = True
@@ -584,7 +590,7 @@
             if f.name == "PROVIDER_INTERFACE":
                 found = True
                 if f.value != clazz.fullname:
-                    error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname))
+                    error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname))
 
     if "extends android.content.BroadcastReceiver" in clazz.raw:
         test_methods = True
@@ -764,15 +770,19 @@
 def verify_exception(clazz):
     """Verifies that methods don't throw generic exceptions."""
     for m in clazz.methods:
-        if "throws java.lang.Exception" in m.raw or "throws java.lang.Throwable" in m.raw or "throws java.lang.Error" in m.raw:
-            error(clazz, m, "S1", "Methods must not throw generic exceptions")
+        for t in m.throws:
+            if t in ["java.lang.Exception", "java.lang.Throwable", "java.lang.Error"]:
+                error(clazz, m, "S1", "Methods must not throw generic exceptions")
 
-        if "throws android.os.RemoteException" in m.raw:
-            if clazz.name == "android.content.ContentProviderClient": continue
-            if clazz.name == "android.os.Binder": continue
-            if clazz.name == "android.os.IBinder": continue
+            if t in ["android.os.RemoteException"]:
+                if clazz.name == "android.content.ContentProviderClient": continue
+                if clazz.name == "android.os.Binder": continue
+                if clazz.name == "android.os.IBinder": continue
 
-            error(clazz, m, "FW9", "Methods calling into system server should rethrow RemoteException as RuntimeException")
+                error(clazz, m, "FW9", "Methods calling into system server should rethrow RemoteException as RuntimeException")
+
+            if len(m.args) == 0 and t in ["java.lang.IllegalArgumentException", "java.lang.NullPointerException"]:
+                warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException")
 
 
 def verify_google(clazz):
@@ -927,7 +937,8 @@
 
     found = {}
     by_name = collections.defaultdict(list)
-    for m in clazz.methods:
+    examine = clazz.ctors + clazz.methods
+    for m in examine:
         if m.name.startswith("unregister"): continue
         if m.name.startswith("remove"): continue
         if re.match("on[A-Z]+", m.name): continue
@@ -971,7 +982,7 @@
         for a in m.args:
             if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"):
                 found = True
-            elif found and a != "android.os.Handler" and a != "java.util.concurrent.Executor":
+            elif found:
                 warn(clazz, m, "M3", "Listeners should always be at end of argument list")
 
 
@@ -1078,16 +1089,11 @@
         "java.nio.BufferOverflowException",
     ]
 
-    test = []
-    test.extend(clazz.ctors)
-    test.extend(clazz.methods)
-
-    for t in test:
-        if " throws " not in t.raw: continue
-        throws = t.raw[t.raw.index(" throws "):]
-        for b in banned:
-            if b in throws:
-                error(clazz, t, None, "Methods must not mention RuntimeException subclasses in throws clauses")
+    examine = clazz.ctors + clazz.methods
+    for m in examine:
+        for t in m.throws:
+            if t in banned:
+                error(clazz, m, None, "Methods must not mention RuntimeException subclasses in throws clauses")
 
 
 def verify_error(clazz):
@@ -1233,6 +1239,58 @@
                 warn(clazz, m, None, "Method argument should be Collection<> (or subclass) instead of raw array")
 
 
+def verify_user_handle(clazz):
+    """Methods taking UserHandle should be ForUser or AsUser."""
+    if clazz.name.endswith("Listener") or clazz.name.endswith("Callback") or clazz.name.endswith("Callbacks"): return
+    if clazz.fullname == "android.app.admin.DeviceAdminReceiver": return
+    if clazz.fullname == "android.content.pm.LauncherApps": return
+    if clazz.fullname == "android.os.UserHandle": return
+    if clazz.fullname == "android.os.UserManager": return
+
+    for m in clazz.methods:
+        if m.name.endswith("AsUser") or m.name.endswith("ForUser"): continue
+        if re.match("on[A-Z]+", m.name): continue
+        if "android.os.UserHandle" in m.args:
+            warn(clazz, m, None, "Method taking UserHandle should be named 'doFooAsUser' or 'queryFooForUser'")
+
+
+def verify_params(clazz):
+    """Parameter classes should be 'Params'."""
+    if clazz.name.endswith("Params"): return
+    if clazz.fullname == "android.app.ActivityOptions": return
+    if clazz.fullname == "android.app.BroadcastOptions": return
+    if clazz.fullname == "android.os.Bundle": return
+    if clazz.fullname == "android.os.BaseBundle": return
+    if clazz.fullname == "android.os.PersistableBundle": return
+
+    bad = ["Param","Parameter","Parameters","Args","Arg","Argument","Arguments","Options","Bundle"]
+    for b in bad:
+        if clazz.name.endswith(b):
+            error(clazz, None, None, "Classes holding a set of parameters should be called 'FooParams'")
+
+
+def verify_services(clazz):
+    """Service name should be FOO_BAR_SERVICE = 'foo_bar'."""
+    if clazz.fullname != "android.content.Context": return
+
+    for f in clazz.fields:
+        if f.typ != "java.lang.String": continue
+        found = re.match(r"([A-Z_]+)_SERVICE", f.name)
+        if found:
+            expected = found.group(1).lower()
+            if f.value != expected:
+                error(clazz, f, "C4", "Inconsistent service value; expected '%s'" % (expected))
+
+
+def verify_tense(clazz):
+    """Verify tenses of method names."""
+    if clazz.fullname.startswith("android.opengl"): return
+
+    for m in clazz.methods:
+        if m.name.endswith("Enable"):
+            warn(clazz, m, None, "Unexpected tense; probably meant 'enabled'")
+
+
 def examine_clazz(clazz):
     """Find all style issues in the given class."""
 
@@ -1290,6 +1348,10 @@
     verify_member_name_not_kotlin_keyword(clazz)
     verify_method_name_not_kotlin_operator(clazz)
     verify_collections_over_arrays(clazz)
+    verify_user_handle(clazz)
+    verify_params(clazz)
+    verify_services(clazz)
+    verify_tense(clazz)
 
 
 def examine_stream(stream):
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 80853b1..0e57f7f 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "Collation.h"
+#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
 
 #include <stdio.h>
 #include <map>
@@ -137,6 +138,16 @@
 }
 
 /**
+ * Gather the enums info.
+ */
+void collate_enums(const EnumDescriptor &enumDescriptor, AtomField *atomField) {
+    for (int i = 0; i < enumDescriptor.value_count(); i++) {
+        atomField->enumValues[enumDescriptor.value(i)->number()] =
+            enumDescriptor.value(i)->name().c_str();
+    }
+}
+
+/**
  * Gather the info about an atom proto.
  */
 int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
@@ -221,11 +232,7 @@
     if (javaType == JAVA_TYPE_ENUM) {
       // All enums are treated as ints when it comes to function signatures.
       signature->push_back(JAVA_TYPE_INT);
-      const EnumDescriptor *enumDescriptor = field->enum_type();
-      for (int i = 0; i < enumDescriptor->value_count(); i++) {
-        atField.enumValues[enumDescriptor->value(i)->number()] =
-            enumDescriptor->value(i)->name().c_str();
-      }
+      collate_enums(*field->enum_type(), &atField);
     } else {
       signature->push_back(javaType);
     }
@@ -235,6 +242,53 @@
   return errorCount;
 }
 
+// This function flattens the fields of the AttributionNode proto in an Atom proto and generates
+// the corresponding atom decl and signature.
+bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl,
+                          vector<java_type_t> *signature) {
+    // Build a sorted list of the fields. Descriptor has them in source file
+    // order.
+    map<int, const FieldDescriptor *> fields;
+    for (int j = 0; j < atom->field_count(); j++) {
+        const FieldDescriptor *field = atom->field(j);
+        fields[field->number()] = field;
+    }
+
+    AtomDecl attributionDecl;
+    vector<java_type_t> attributionSignature;
+    collate_atom(android::os::statsd::AttributionNode::descriptor(),
+                 &attributionDecl, &attributionSignature);
+
+    // Build the type signature and the atom data.
+    bool has_attribution_node = false;
+    for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
+        it != fields.end(); it++) {
+        const FieldDescriptor *field = it->second;
+        java_type_t javaType = java_type(field);
+        if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+            atomDecl->fields.insert(
+                atomDecl->fields.end(),
+                attributionDecl.fields.begin(), attributionDecl.fields.end());
+            signature->insert(
+                signature->end(),
+                attributionSignature.begin(), attributionSignature.end());
+            has_attribution_node = true;
+
+        } else {
+            AtomField atField(field->name(), javaType);
+            if (javaType == JAVA_TYPE_ENUM) {
+                // All enums are treated as ints when it comes to function signatures.
+                signature->push_back(JAVA_TYPE_INT);
+                collate_enums(*field->enum_type(), &atField);
+            } else {
+                signature->push_back(javaType);
+            }
+            atomDecl->fields.push_back(atField);
+        }
+    }
+    return has_attribution_node;
+}
+
 /**
  * Gather the info about the atoms.
  */
@@ -266,6 +320,13 @@
     errorCount += collate_atom(atom, &atomDecl, &signature);
     atoms->signatures.insert(signature);
     atoms->decls.insert(atomDecl);
+
+    AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
+    vector<java_type_t> nonChainedSignature;
+    if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
+        atoms->non_chained_signatures.insert(nonChainedSignature);
+        atoms->non_chained_decls.insert(nonChainedAtomDecl);
+    }
   }
 
   if (dbg) {
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index cd0625c..0455eca 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -32,6 +32,7 @@
 using std::string;
 using std::vector;
 using google::protobuf::Descriptor;
+using google::protobuf::FieldDescriptor;
 
 /**
  * The types for atom parameters.
@@ -93,14 +94,15 @@
 struct Atoms {
     set<vector<java_type_t>> signatures;
     set<AtomDecl> decls;
+    set<AtomDecl> non_chained_decls;
+    set<vector<java_type_t>> non_chained_signatures;
 };
 
 /**
  * Gather the information about the atoms.  Returns the number of errors.
  */
 int collate_atoms(const Descriptor* descriptor, Atoms* atoms);
-int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
-                 vector<java_type_t> *signature);
+int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, vector<java_type_t> *signature);
 
 }  // namespace stats_log_api_gen
 }  // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index bbe6d63..e0e6b58 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -195,6 +195,47 @@
         fprintf(out, "\n");
     }
 
+    for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
+        signature != atoms.non_chained_signatures.end(); signature++) {
+        int argIndex;
+
+        fprintf(out, "void\n");
+        fprintf(out, "stats_write_non_chained(int32_t code");
+        argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+            arg != signature->end(); arg++) {
+            fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+            argIndex++;
+        }
+        fprintf(out, ")\n");
+
+        fprintf(out, "{\n");
+        argIndex = 1;
+        fprintf(out, "    android_log_event_list event(kStatsEventTag);\n");
+        fprintf(out, "    event << code;\n\n");
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+            arg != signature->end(); arg++) {
+            if (argIndex == 1) {
+                fprintf(out, "    event.begin();\n\n");
+                fprintf(out, "    event.begin();\n");
+            }
+            if (*arg == JAVA_TYPE_STRING) {
+                fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
+                fprintf(out, "        arg%d = \"\";\n", argIndex);
+                fprintf(out, "    }\n");
+            }
+            fprintf(out, "    event << arg%d;\n", argIndex);
+            if (argIndex == 2) {
+                fprintf(out, "    event.end();\n\n");
+                fprintf(out, "    event.end();\n\n");
+            }
+            argIndex++;
+        }
+
+        fprintf(out, "    event.write(LOG_ID_STATS);\n");
+        fprintf(out, "}\n");
+        fprintf(out, "\n");
+    }
     // Print footer
     fprintf(out, "\n");
     fprintf(out, "} // namespace util\n");
@@ -203,6 +244,68 @@
     return 0;
 }
 
+void build_non_chained_decl_map(const Atoms& atoms,
+                                std::map<int, set<AtomDecl>::const_iterator>* decl_map){
+    for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
+        atom != atoms.non_chained_decls.end(); atom++) {
+        decl_map->insert(std::make_pair(atom->code, atom));
+    }
+}
+
+static void write_cpp_usage(
+    FILE* out, const string& method_name, const string& atom_code_name,
+    const AtomDecl& atom, const AtomDecl &attributionDecl) {
+    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
+    for (vector<AtomField>::const_iterator field = atom.fields.begin();
+            field != atom.fields.end(); field++) {
+        if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+            for (auto chainField : attributionDecl.fields) {
+                if (chainField.javaType == JAVA_TYPE_STRING) {
+                    fprintf(out, ", const std::vector<%s>& %s",
+                         cpp_type_name(chainField.javaType),
+                         chainField.name.c_str());
+                } else {
+                    fprintf(out, ", const %s* %s, size_t %s_length",
+                         cpp_type_name(chainField.javaType),
+                         chainField.name.c_str(), chainField.name.c_str());
+                }
+            }
+        } else {
+            fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
+        }
+    }
+    fprintf(out, ");\n");
+}
+
+static void write_cpp_method_header(
+    FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
+    const AtomDecl &attributionDecl) {
+    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
+            signature != signatures.end(); signature++) {
+        fprintf(out, "void %s(int32_t code ", method_name.c_str());
+        int argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+            arg != signature->end(); arg++) {
+            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+                for (auto chainField : attributionDecl.fields) {
+                    if (chainField.javaType == JAVA_TYPE_STRING) {
+                        fprintf(out, ", const std::vector<%s>& %s",
+                            cpp_type_name(chainField.javaType), chainField.name.c_str());
+                    } else {
+                        fprintf(out, ", const %s* %s, size_t %s_length",
+                            cpp_type_name(chainField.javaType),
+                            chainField.name.c_str(), chainField.name.c_str());
+                    }
+                }
+            } else {
+                fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+            }
+            argIndex++;
+        }
+        fprintf(out, ");\n");
+
+    }
+}
 
 static int
 write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
@@ -228,6 +331,9 @@
     fprintf(out, " */\n");
     fprintf(out, "enum {\n");
 
+    std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
+    build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
+
     size_t i = 0;
     // Print constants
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
@@ -236,26 +342,13 @@
         fprintf(out, "\n");
         fprintf(out, "    /**\n");
         fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
-        fprintf(out, "     * Usage: stats_write(StatsLog.%s", constant.c_str());
-        for (vector<AtomField>::const_iterator field = atom->fields.begin();
-                field != atom->fields.end(); field++) {
-            if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
-                    if (chainField.javaType == JAVA_TYPE_STRING) {
-                        fprintf(out, ", const std::vector<%s>& %s",
-                             cpp_type_name(chainField.javaType),
-                             chainField.name.c_str());
-                    } else {
-                        fprintf(out, ", const %s* %s, size_t %s_length",
-                             cpp_type_name(chainField.javaType),
-                             chainField.name.c_str(), chainField.name.c_str());
-                    }
-                }
-            } else {
-                fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
-            }
+        write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
+
+        auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
+        if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
+            write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
+                attributionDecl);
         }
-        fprintf(out, ");\n");
         fprintf(out, "     */\n");
         char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
         fprintf(out, "    %s = %d%s\n", constant.c_str(), atom->code, comma);
@@ -274,30 +367,13 @@
     fprintf(out, "//\n");
     fprintf(out, "// Write methods\n");
     fprintf(out, "//\n");
-    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
-            signature != atoms.signatures.end(); signature++) {
-        fprintf(out, "void stats_write(int32_t code ");
-        int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
-            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
-                    if (chainField.javaType == JAVA_TYPE_STRING) {
-                        fprintf(out, ", const std::vector<%s>& %s",
-                            cpp_type_name(chainField.javaType), chainField.name.c_str());
-                    } else {
-                        fprintf(out, ", const %s* %s, size_t %s_length",
-                            cpp_type_name(chainField.javaType),
-                            chainField.name.c_str(), chainField.name.c_str());
-                    }
-                }
-            } else {
-                fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
-            }
-            argIndex++;
-        }
-        fprintf(out, ");\n");
-    }
+    write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl);
+
+    fprintf(out, "//\n");
+    fprintf(out, "// Write flattened methods\n");
+    fprintf(out, "//\n");
+    write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures,
+        attributionDecl);
 
     fprintf(out, "\n");
     fprintf(out, "} // namespace util\n");
@@ -306,6 +382,49 @@
     return 0;
 }
 
+static void write_java_usage(
+    FILE* out, const string& method_name, const string& atom_code_name,
+    const AtomDecl& atom, const AtomDecl &attributionDecl) {
+    fprintf(out, "     * Usage: StatsLog.%s(StatsLog.%s",
+        method_name.c_str(), atom_code_name.c_str());
+    for (vector<AtomField>::const_iterator field = atom.fields.begin();
+        field != atom.fields.end(); field++) {
+        if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+            for (auto chainField : attributionDecl.fields) {
+                fprintf(out, ", %s[] %s",
+                    java_type_name(chainField.javaType), chainField.name.c_str());
+            }
+        } else {
+            fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
+        }
+    }
+    fprintf(out, ");\n");
+}
+
+static void write_java_method(
+    FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
+    const AtomDecl &attributionDecl) {
+    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
+        signature != signatures.end(); signature++) {
+        fprintf(out, "    public static native void %s(int code", method_name.c_str());
+        int argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+            arg != signature->end(); arg++) {
+            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+                for (auto chainField : attributionDecl.fields) {
+                    fprintf(out, ", %s[] %s",
+                        java_type_name(chainField.javaType), chainField.name.c_str());
+                }
+            } else {
+                fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+            }
+            argIndex++;
+        }
+        fprintf(out, ");\n");
+    }
+}
+
+
 static int
 write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
 {
@@ -322,6 +441,9 @@
     fprintf(out, "public class StatsLogInternal {\n");
     fprintf(out, "    // Constants for atom codes.\n");
 
+    std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
+    build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
+
     // Print constants for the atom codes.
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
             atom != atoms.decls.end(); atom++) {
@@ -329,19 +451,12 @@
         fprintf(out, "\n");
         fprintf(out, "    /**\n");
         fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
-        fprintf(out, "     * Usage: StatsLog.write(StatsLog.%s", constant.c_str());
-        for (vector<AtomField>::const_iterator field = atom->fields.begin();
-            field != atom->fields.end(); field++) {
-            if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
-                    fprintf(out, ", %s[] %s",
-                        java_type_name(chainField.javaType), chainField.name.c_str());
-                }
-            } else {
-                fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
-            }
+        write_java_usage(out, "write", constant, *atom, attributionDecl);
+        auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
+        if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
+            write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second,
+             attributionDecl);
         }
-        fprintf(out, ");\n");
         fprintf(out, "     */\n");
         fprintf(out, "    public static final int %s = %d;\n", constant.c_str(), atom->code);
     }
@@ -371,24 +486,8 @@
 
     // Print write methods
     fprintf(out, "    // Write methods\n");
-    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
-        signature != atoms.signatures.end(); signature++) {
-        fprintf(out, "    public static native void write(int code");
-        int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
-            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
-                    fprintf(out, ", %s[] %s",
-                        java_type_name(chainField.javaType), chainField.name.c_str());
-                }
-            } else {
-                fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
-            }
-            argIndex++;
-        }
-        fprintf(out, ");\n");
-    }
+    write_java_method(out, "write", atoms.signatures, attributionDecl);
+    write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
 
     fprintf(out, "}\n");
 
@@ -431,9 +530,9 @@
 }
 
 static string
-jni_function_name(const vector<java_type_t>& signature)
+jni_function_name(const string& method_name, const vector<java_type_t>& signature)
 {
-    string result("StatsLog_write");
+    string result("StatsLog_" + method_name);
     for (vector<java_type_t>::const_iterator arg = signature.begin();
         arg != signature.end(); arg++) {
         switch (*arg) {
@@ -509,34 +608,17 @@
 }
 
 static int
-write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
+write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
+    const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
 {
-    // Print prelude
-    fprintf(out, "// This file is autogenerated\n");
-    fprintf(out, "\n");
-
-    fprintf(out, "#include <statslog.h>\n");
-    fprintf(out, "\n");
-    fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
-    fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
-    fprintf(out, "#include <utils/Vector.h>\n");
-    fprintf(out, "#include \"core_jni_helpers.h\"\n");
-    fprintf(out, "#include \"jni.h\"\n");
-    fprintf(out, "\n");
-    fprintf(out, "#define UNUSED  __attribute__((__unused__))\n");
-    fprintf(out, "\n");
-
-    fprintf(out, "namespace android {\n");
-    fprintf(out, "\n");
-
     // Print write methods
-    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
-        signature != atoms.signatures.end(); signature++) {
+    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
+        signature != signatures.end(); signature++) {
         int argIndex;
 
         fprintf(out, "static void\n");
         fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
-                jni_function_name(*signature).c_str());
+                jni_function_name(java_method_name, *signature).c_str());
         argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
@@ -624,7 +706,7 @@
 
         // stats_write call
         argIndex = 1;
-        fprintf(out, "    android::util::stats_write(code");
+        fprintf(out, "    android::util::%s(code", cpp_method_name.c_str());
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -675,17 +757,53 @@
         fprintf(out, "\n");
     }
 
+
+    return 0;
+}
+
+void write_jni_registration(FILE* out, const string& java_method_name,
+    const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) {
+    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
+            signature != signatures.end(); signature++) {
+        fprintf(out, "    { \"%s\", \"%s\", (void*)%s },\n",
+            java_method_name.c_str(),
+            jni_function_signature(*signature, attributionDecl).c_str(),
+            jni_function_name(java_method_name, *signature).c_str());
+    }
+}
+
+static int
+write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
+{
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "#include <statslog.h>\n");
+    fprintf(out, "\n");
+    fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
+    fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
+    fprintf(out, "#include <utils/Vector.h>\n");
+    fprintf(out, "#include \"core_jni_helpers.h\"\n");
+    fprintf(out, "#include \"jni.h\"\n");
+    fprintf(out, "\n");
+    fprintf(out, "#define UNUSED  __attribute__((__unused__))\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "namespace android {\n");
+    fprintf(out, "\n");
+
+    write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl);
+    write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
+        atoms.non_chained_signatures, attributionDecl);
+
     // Print registration function table
     fprintf(out, "/*\n");
     fprintf(out, " * JNI registration.\n");
     fprintf(out, " */\n");
     fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
-    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
-            signature != atoms.signatures.end(); signature++) {
-        fprintf(out, "    { \"write\", \"%s\", (void*)%s },\n",
-            jni_function_signature(*signature, attributionDecl).c_str(),
-            jni_function_name(*signature).c_str());
-    }
+    write_jni_registration(out, "write", atoms.signatures, attributionDecl);
+    write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
@@ -699,11 +817,9 @@
 
     fprintf(out, "\n");
     fprintf(out, "} // namespace android\n");
-
     return 0;
 }
 
-
 static void
 print_usage()
 {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0dd964c..70d6ce4 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -28,7 +28,6 @@
 import android.net.wifi.ScanSettings;
 import android.net.wifi.ScanResult;
 import android.net.wifi.PasspointManagementObjectDefinition;
-import android.net.wifi.WifiConnectionStatistics;
 import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.Network;
 
@@ -166,8 +165,6 @@
 
     void enableWifiConnectivityManager(boolean enabled);
 
-    WifiConnectionStatistics getConnectionStatistics();
-
     void disableEphemeralNetwork(String SSID);
 
     void factoryReset();
diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl b/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl
deleted file mode 100644
index 601face..0000000
--- a/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
- *
- *     http://www.apache.org/licenses/LICENSE-2.0 
- *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-parcelable WifiConnectionStatistics;
diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.java b/wifi/java/android/net/wifi/WifiConnectionStatistics.java
deleted file mode 100644
index 1120c66..0000000
--- a/wifi/java/android/net/wifi/WifiConnectionStatistics.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.annotation.SystemApi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.util.HashMap;
-
-/**
- * Wifi Connection Statistics: gather various stats regarding WiFi connections,
- * connection requests, auto-join
- * and WiFi usage.
- * @hide
- * @removed
- */
-@SystemApi
-public class WifiConnectionStatistics implements Parcelable {
-    private static final String TAG = "WifiConnnectionStatistics";
-
-    /**
-     *  history of past connection to untrusted SSID
-     *  Key = SSID
-     *  Value = num connection
-     */
-    public HashMap<String, WifiNetworkConnectionStatistics> untrustedNetworkHistory;
-
-    // Number of time we polled the chip and were on 5GHz
-    public int num5GhzConnected;
-
-    // Number of time we polled the chip and were on 2.4GHz
-    public int num24GhzConnected;
-
-    // Number autojoin attempts
-    public int numAutoJoinAttempt;
-
-    // Number auto-roam attempts
-    public int numAutoRoamAttempt;
-
-    // Number wifimanager join attempts
-    public int numWifiManagerJoinAttempt;
-
-    public WifiConnectionStatistics() {
-        untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>();
-    }
-
-    public void incrementOrAddUntrusted(String SSID, int connection, int usage) {
-        WifiNetworkConnectionStatistics stats;
-        if (TextUtils.isEmpty(SSID))
-            return;
-        if (untrustedNetworkHistory.containsKey(SSID)) {
-            stats = untrustedNetworkHistory.get(SSID);
-            if (stats != null){
-                stats.numConnection = connection + stats.numConnection;
-                stats.numUsage = usage + stats.numUsage;
-            }
-        } else {
-            stats = new WifiNetworkConnectionStatistics(connection, usage);
-        }
-        if (stats != null) {
-            untrustedNetworkHistory.put(SSID, stats);
-        }
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sbuf = new StringBuilder();
-        sbuf.append("Connected on: 2.4Ghz=").append(num24GhzConnected);
-        sbuf.append(" 5Ghz=").append(num5GhzConnected).append("\n");
-        sbuf.append(" join=").append(numWifiManagerJoinAttempt);
-        sbuf.append("\\").append(numAutoJoinAttempt).append("\n");
-        sbuf.append(" roam=").append(numAutoRoamAttempt).append("\n");
-
-        for (String Key : untrustedNetworkHistory.keySet()) {
-            WifiNetworkConnectionStatistics stats = untrustedNetworkHistory.get(Key);
-            if (stats != null) {
-                sbuf.append(Key).append(" ").append(stats.toString()).append("\n");
-            }
-        }
-        return sbuf.toString();
-    }
-
-    /** copy constructor*/
-    public WifiConnectionStatistics(WifiConnectionStatistics source) {
-        untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>();
-        if (source != null) {
-            untrustedNetworkHistory.putAll(source.untrustedNetworkHistory);
-        }
-    }
-
-    /** Implement the Parcelable interface */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(num24GhzConnected);
-        dest.writeInt(num5GhzConnected);
-        dest.writeInt(numAutoJoinAttempt);
-        dest.writeInt(numAutoRoamAttempt);
-        dest.writeInt(numWifiManagerJoinAttempt);
-
-        dest.writeInt(untrustedNetworkHistory.size());
-        for (String Key : untrustedNetworkHistory.keySet()) {
-            WifiNetworkConnectionStatistics num = untrustedNetworkHistory.get(Key);
-            dest.writeString(Key);
-            dest.writeInt(num.numConnection);
-            dest.writeInt(num.numUsage);
-
-        }
-    }
-
-    /** Implement the Parcelable interface */
-    public static final Creator<WifiConnectionStatistics> CREATOR =
-        new Creator<WifiConnectionStatistics>() {
-            public WifiConnectionStatistics createFromParcel(Parcel in) {
-                WifiConnectionStatistics stats = new WifiConnectionStatistics();
-                stats.num24GhzConnected = in.readInt();
-                stats.num5GhzConnected = in.readInt();
-                stats.numAutoJoinAttempt = in.readInt();
-                stats.numAutoRoamAttempt = in.readInt();
-                stats.numWifiManagerJoinAttempt = in.readInt();
-                int n = in.readInt();
-                while (n-- > 0) {
-                    String Key = in.readString();
-                    int numConnection = in.readInt();
-                    int numUsage = in.readInt();
-                    WifiNetworkConnectionStatistics st =
-                            new WifiNetworkConnectionStatistics(numConnection, numUsage);
-                    stats.untrustedNetworkHistory.put(Key, st);
-                }
-                return stats;
-            }
-
-            public WifiConnectionStatistics[] newArray(int size) {
-                return new WifiConnectionStatistics[size];
-            }
-        };
-}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 70e83db..aa75a07 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -999,20 +999,6 @@
     }
 
     /**
-     * @hide
-     * @removed
-     */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL)
-    public WifiConnectionStatistics getConnectionStatistics() {
-        try {
-            return mService.getConnectionStatistics();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Returns a WifiConfiguration matching this ScanResult
      *
      * @param scanResult scanResult that represents the BSSID