Merge "Initial seed for boot profiles."
diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
new file mode 100644
index 0000000..4e2b281
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.wm;
+
+import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_COEFFICIENT_VAR;
+import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_ITERATION;
+import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_MEAN;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.hamcrest.core.AnyOf.anyOf;
+import static org.hamcrest.core.Is.is;
+
+import android.app.Activity;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
+import android.perftests.utils.PerfManualStatusReporter;
+import android.perftests.utils.StubActivity;
+import android.util.Pair;
+import android.view.IRecentsAnimationController;
+import android.view.IRecentsAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
+import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
+import androidx.test.runner.lifecycle.Stage;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
+    private static Intent sRecentsIntent;
+
+    @Rule
+    public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
+
+    @Rule
+    public final ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule<>(
+            StubActivity.class, false /* initialTouchMode */, false /* launchActivity */);
+
+    private long mMeasuredTimeNs;
+    private LifecycleListener mLifecycleListener;
+
+    @Parameterized.Parameter(0)
+    public int intervalBetweenOperations;
+
+    @Parameterized.Parameters(name = "interval{0}ms")
+    public static Collection<Object[]> getParameters() {
+        return Arrays.asList(new Object[][] {
+                { 0 },
+                { 100 },
+                { 300 },
+        });
+    }
+
+    @BeforeClass
+    public static void setUpClass() {
+        // Get the permission to invoke startRecentsActivity.
+        sUiAutomation.adoptShellPermissionIdentity();
+
+        final Context context = getInstrumentation().getContext();
+        final PackageManager pm = context.getPackageManager();
+        final ComponentName defaultHome = pm.getHomeActivities(new ArrayList<>());
+
+        try {
+            final ComponentName recentsComponent =
+                    ComponentName.unflattenFromString(context.getResources().getString(
+                            com.android.internal.R.string.config_recentsComponentName));
+            final int enabledState = pm.getComponentEnabledSetting(recentsComponent);
+            Assume.assumeThat(enabledState, anyOf(
+                    is(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
+                    is(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)));
+
+            final boolean homeIsRecents =
+                    recentsComponent.getPackageName().equals(defaultHome.getPackageName());
+            sRecentsIntent =
+                    new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent);
+        } catch (Exception e) {
+            Assume.assumeNoException(e);
+        }
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        sUiAutomation.dropShellPermissionIdentity();
+    }
+
+    @Before
+    @Override
+    public void setUp() {
+        super.setUp();
+        final Activity testActivity = mActivityRule.launchActivity(null /* intent */);
+        try {
+            mActivityRule.runOnUiThread(() -> testActivity.getWindow()
+                    .addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
+        } catch (Throwable ignored) { }
+        mLifecycleListener = new LifecycleListener(testActivity);
+        ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(mLifecycleListener);
+    }
+
+    @After
+    public void tearDown() {
+        ActivityLifecycleMonitorRegistry.getInstance().removeLifecycleCallback(mLifecycleListener);
+    }
+
+    /** Simulate the timing of touch. */
+    private void makeInterval() {
+        SystemClock.sleep(intervalBetweenOperations);
+    }
+
+    /**
+     * <pre>
+     * Steps:
+     * (1) Start recents activity (only make it visible).
+     * (2) Finish animation, take turns to execute (a), (b).
+     *     (a) Move recents activity to top.
+     * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_TOP})
+     *         Move test app to top by startActivityFromRecents.
+     *     (b) Cancel (it is similar to swipe a little distance and give up to enter recents).
+     * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_ORIGINAL_POSITION})
+     * (3) Loop (1).
+     * </pre>
+     */
+    @Test
+    @ManualBenchmarkTest(
+            warmupDurationNs = TIME_1_S_IN_NS,
+            targetTestDurationNs = TIME_5_S_IN_NS,
+            statsReportFlags =
+                    STATS_REPORT_ITERATION | STATS_REPORT_MEAN | STATS_REPORT_COEFFICIENT_VAR)
+    public void testRecentsAnimation() throws Throwable {
+        final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final IActivityTaskManager atm = ActivityTaskManager.getService();
+
+        final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>();
+        // Real launch the recents activity.
+        finishCases.add(new Pair<>("finishMoveToTop", true));
+        // Return to the original top.
+        finishCases.add(new Pair<>("finishCancel", false));
+
+        // Ensure startRecentsActivity won't be called before finishing the animation.
+        final Semaphore recentsSemaphore = new Semaphore(1);
+
+        final int testActivityTaskId = mActivityRule.getActivity().getTaskId();
+        final IRecentsAnimationRunner.Stub anim = new IRecentsAnimationRunner.Stub() {
+            int mIteration;
+
+            @Override
+            public void onAnimationStart(IRecentsAnimationController controller,
+                    RemoteAnimationTarget[] apps, Rect homeContentInsets,
+                    Rect minimizedHomeBounds) throws RemoteException {
+                final Pair<String, Boolean> finishCase = finishCases.get(mIteration++ % 2);
+                final boolean moveRecentsToTop = finishCase.second;
+                makeInterval();
+
+                long startTime = SystemClock.elapsedRealtimeNanos();
+                controller.finish(moveRecentsToTop, false /* sendUserLeaveHint */);
+                final long elapsedTimeNsOfFinish = SystemClock.elapsedRealtimeNanos() - startTime;
+                mMeasuredTimeNs += elapsedTimeNsOfFinish;
+                state.addExtraResult(finishCase.first, elapsedTimeNsOfFinish);
+
+                if (moveRecentsToTop) {
+                    mLifecycleListener.waitForIdleSync(Stage.STOPPED);
+
+                    startTime = SystemClock.elapsedRealtimeNanos();
+                    atm.startActivityFromRecents(testActivityTaskId, null /* options */);
+                    final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
+                    mMeasuredTimeNs += elapsedTimeNs;
+                    state.addExtraResult("startFromRecents", elapsedTimeNs);
+
+                    mLifecycleListener.waitForIdleSync(Stage.RESUMED);
+                }
+
+                makeInterval();
+                recentsSemaphore.release();
+            }
+
+            @Override
+            public void onAnimationCanceled(boolean deferredWithScreenshot) throws RemoteException {
+                Assume.assumeNoException(
+                        new AssertionError("onAnimationCanceled should not be called"));
+            }
+        };
+
+        while (state.keepRunning(mMeasuredTimeNs)) {
+            Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS));
+
+            final long startTime = SystemClock.elapsedRealtimeNanos();
+            atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim);
+            final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime;
+            mMeasuredTimeNs += elapsedTimeNsOfStart;
+            state.addExtraResult("start", elapsedTimeNsOfStart);
+        }
+
+        // Ensure the last round of animation callback is done.
+        recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS);
+        recentsSemaphore.release();
+    }
+
+    private static class LifecycleListener implements ActivityLifecycleCallback {
+        private final Activity mTargetActivity;
+        private Stage mWaitingStage;
+        private Stage mReceivedStage;
+
+        LifecycleListener(Activity activity) {
+            mTargetActivity = activity;
+        }
+
+        void waitForIdleSync(Stage state) {
+            synchronized (this) {
+                if (state != mReceivedStage) {
+                    mWaitingStage = state;
+                    try {
+                        wait(TimeUnit.NANOSECONDS.toMillis(TIME_5_S_IN_NS));
+                    } catch (InterruptedException impossible) { }
+                }
+                mWaitingStage = mReceivedStage = null;
+            }
+            getInstrumentation().waitForIdleSync();
+        }
+
+        @Override
+        public void onActivityLifecycleChanged(Activity activity, Stage stage) {
+            if (mTargetActivity != activity) {
+                return;
+            }
+
+            synchronized (this) {
+                mReceivedStage = stage;
+                if (mWaitingStage == mReceivedStage) {
+                    notifyAll();
+                }
+            }
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
index a951869..27790e6 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
@@ -60,7 +60,7 @@
     }
 
     @Test
-    @ManualBenchmarkTest(warmupDurationNs = WARMUP_DURATION, targetTestDurationNs = TEST_DURATION)
+    @ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS)
     public void testAddRemoveWindow() throws Throwable {
         new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState());
     }
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
index b2c6168..4864da4 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
@@ -25,8 +25,8 @@
 public class WindowManagerPerfTestBase {
     static final UiAutomation sUiAutomation = getInstrumentation().getUiAutomation();
     static final long NANOS_PER_S = 1000L * 1000 * 1000;
-    static final long WARMUP_DURATION = 1 * NANOS_PER_S;
-    static final long TEST_DURATION = 5 * NANOS_PER_S;
+    static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
+    static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S;
 
     @Before
     public void setUp() {
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
index dd43ae7..ffe39e8 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -16,6 +16,7 @@
 
 package android.perftests.utils;
 
+import android.annotation.IntDef;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.Bundle;
@@ -58,6 +59,28 @@
 public final class ManualBenchmarkState {
     private static final String TAG = ManualBenchmarkState.class.getSimpleName();
 
+    @IntDef(prefix = {"STATS_REPORT"}, value = {
+            STATS_REPORT_MEDIAN,
+            STATS_REPORT_MEAN,
+            STATS_REPORT_MIN,
+            STATS_REPORT_MAX,
+            STATS_REPORT_PERCENTILE90,
+            STATS_REPORT_PERCENTILE95,
+            STATS_REPORT_STDDEV,
+            STATS_REPORT_ITERATION,
+    })
+    public @interface StatsReport {}
+
+    public static final int STATS_REPORT_MEDIAN = 0x00000001;
+    public static final int STATS_REPORT_MEAN = 0x00000002;
+    public static final int STATS_REPORT_MIN = 0x00000004;
+    public static final int STATS_REPORT_MAX = 0x00000008;
+    public static final int STATS_REPORT_PERCENTILE90 = 0x00000010;
+    public static final int STATS_REPORT_PERCENTILE95 = 0x00000020;
+    public static final int STATS_REPORT_STDDEV = 0x00000040;
+    public static final int STATS_REPORT_COEFFICIENT_VAR = 0x00000080;
+    public static final int STATS_REPORT_ITERATION = 0x00000100;
+
     // TODO: Tune these values.
     // warm-up for duration
     private static final long WARMUP_DURATION_NS = TimeUnit.SECONDS.toNanos(5);
@@ -93,6 +116,13 @@
     // The computation needs double precision, but long int is fine for final reporting.
     private Stats mStats;
 
+    private int mStatsReportFlags = STATS_REPORT_MEDIAN | STATS_REPORT_MEAN
+            | STATS_REPORT_PERCENTILE90 | STATS_REPORT_PERCENTILE95 | STATS_REPORT_STDDEV;
+
+    private boolean shouldReport(int statsReportFlag) {
+        return (mStatsReportFlags & statsReportFlag) != 0;
+    }
+
     void configure(ManualBenchmarkTest testAnnotation) {
         if (testAnnotation == null) {
             return;
@@ -106,6 +136,10 @@
         if (targetTestDurationNs >= 0) {
             mTargetTestDurationNs = targetTestDurationNs;
         }
+        final int statsReportFlags = testAnnotation.statsReportFlags();
+        if (statsReportFlags >= 0) {
+            mStatsReportFlags = statsReportFlags;
+        }
     }
 
     private void beginBenchmark(long warmupDuration, int iterations) {
@@ -186,12 +220,35 @@
         return sb.toString();
     }
 
-    private static void fillStatus(Bundle status, String key, Stats stats) {
-        status.putLong(key + "_median", stats.getMedian());
-        status.putLong(key + "_mean", (long) stats.getMean());
-        status.putLong(key + "_percentile90", stats.getPercentile90());
-        status.putLong(key + "_percentile95", stats.getPercentile95());
-        status.putLong(key + "_stddev", (long) stats.getStandardDeviation());
+    private void fillStatus(Bundle status, String key, Stats stats) {
+        if (shouldReport(STATS_REPORT_ITERATION)) {
+            status.putLong(key + "_iteration", stats.getSize());
+        }
+        if (shouldReport(STATS_REPORT_MEDIAN)) {
+            status.putLong(key + "_median", stats.getMedian());
+        }
+        if (shouldReport(STATS_REPORT_MEAN)) {
+            status.putLong(key + "_mean", Math.round(stats.getMean()));
+        }
+        if (shouldReport(STATS_REPORT_MIN)) {
+            status.putLong(key + "_min", stats.getMin());
+        }
+        if (shouldReport(STATS_REPORT_MAX)) {
+            status.putLong(key + "_max", stats.getMax());
+        }
+        if (shouldReport(STATS_REPORT_PERCENTILE90)) {
+            status.putLong(key + "_percentile90", stats.getPercentile90());
+        }
+        if (shouldReport(STATS_REPORT_PERCENTILE95)) {
+            status.putLong(key + "_percentile95", stats.getPercentile95());
+        }
+        if (shouldReport(STATS_REPORT_STDDEV)) {
+            status.putLong(key + "_stddev", Math.round(stats.getStandardDeviation()));
+        }
+        if (shouldReport(STATS_REPORT_COEFFICIENT_VAR)) {
+            status.putLong(key + "_cv",
+                    Math.round((100 * stats.getStandardDeviation() / stats.getMean())));
+        }
     }
 
     public void sendFullStatusReport(Instrumentation instrumentation, String key) {
@@ -204,8 +261,9 @@
         if (mExtraResults != null) {
             for (int i = 0; i < mExtraResults.size(); i++) {
                 final String subKey = key + "_" + mExtraResults.keyAt(i);
-                final Stats stats = new Stats(mExtraResults.valueAt(i));
-                Log.i(TAG, summaryLine(subKey, mStats, mResults));
+                final ArrayList<Long> results = mExtraResults.valueAt(i);
+                final Stats stats = new Stats(results);
+                Log.i(TAG, summaryLine(subKey, stats, results));
                 fillStatus(status, subKey, stats);
             }
         }
@@ -218,5 +276,6 @@
     public @interface ManualBenchmarkTest {
         long warmupDurationNs() default -1;
         long targetTestDurationNs() default -1;
+        @StatsReport int statsReportFlags() default -1;
     }
 }
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java b/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java
index 5e50073..f650e81 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java
@@ -23,6 +23,7 @@
 public class Stats {
     private long mMedian, mMin, mMax, mPercentile90, mPercentile95;
     private double mMean, mStandardDeviation;
+    private final int mSize;
 
     /* Calculate stats in constructor. */
     public Stats(List<Long> values) {
@@ -35,6 +36,7 @@
 
         Collections.sort(values);
 
+        mSize = size;
         mMin = values.get(0);
         mMax = values.get(values.size() - 1);
 
@@ -56,6 +58,10 @@
         mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1));
     }
 
+    public int getSize() {
+        return mSize;
+    }
+
     public double getMean() {
         return mMean;
     }
diff --git a/apex/jobscheduler/README_js-mainline.md b/apex/jobscheduler/README_js-mainline.md
new file mode 100644
index 0000000..b5fea5e
--- /dev/null
+++ b/apex/jobscheduler/README_js-mainline.md
@@ -0,0 +1,51 @@
+# Making Job Scheduler into a Mainline Module
+
+## TODOs
+
+See also:
+- http://go/moving-js-code-for-mainline
+- http://go/jobscheduler-code-dependencies-2019-07
+
+- [ ] Move client code
+  - [ ] Move code
+  - [ ] Make build file
+  - [ ] "m jobscheduler-framework" pass
+  - [ ] "m framework" pass
+  - [ ] "m service" pass
+- [ ] Move proto
+  - No, couldn't do it, because it's referred to by incidentd_proto
+- [ ] Move service
+  - [X] Move code (done, but it won't compile yet)
+  - [X] Make build file
+  - [X] "m service" pass
+  - [X] "m jobscheduler-service" pass
+    - To make it pass, jobscheduler-service has to link services.jar too. Many dependencies.
+- [ ] Move this into `frameworks/apex/jobscheduler/...`. Currently it's in `frameworks/base/apex/...`
+because `frameworks/apex/` is not a part of any git projects. (and also working on multiple
+projects is a pain.)
+
+
+## Problems
+- Couldn't move dumpsys proto files. They are used by incidentd_proto, which is in the platform
+  (not updatable).
+  - One idea is *not* to move the proto files into apex but keep them in the platform.
+    Then we make sure to extend the proto files in a backward-compat way (which we do anyway)
+    and always use the latest file from the JS apex.
+
+- There are a lot of build tasks that use "framework.jar". (Examples: hiddenapi-greylist.txt check,
+  update-api / public API check and SDK stub (android.jar) creation)
+  To make the downstream build modules buildable, we need to include js-framework.jar in
+  framework.jar. However it turned out to be tricky because soong has special logic for "framework"
+  and "framework.jar".
+  i.e. Conceptually, we can do it by renaming `framework` to `framework-minus-jobscheduler`, build
+  `jobscheduler-framework` with `framework-minus-jobscheduler`, and create `framework` by merging
+  `framework-minus-jobscheduler` and `jobscheduler-framework`.
+  However it didn't quite work because of the special casing.
+
+- JS-service uses a lot of other code in `services`, so it needs to link services.core.jar e.g.
+ - Common system service code, e.g. `com.android.server.SystemService`
+ - Common utility code, e.g. `FgThread` and `IoThread`
+ - Other system services such as `DeviceIdleController` and `ActivityManagerService`
+ - Server side singleton. `AppStateTracker`
+ - `DeviceIdleController.LocalService`, which is a local service but there's no interface class.
+ - `XxxInternal` interfaces that are not in the framework side. -> We should be able to move them.
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
new file mode 100644
index 0000000..ca6dc45
--- /dev/null
+++ b/apex/jobscheduler/service/Android.bp
@@ -0,0 +1,15 @@
+// Job Scheduler Service jar, which will eventually be put in the jobscheduler mainline apex.
+// jobscheduler-service needs to be added to PRODUCT_SYSTEM_SERVER_JARS.
+java_library {
+    name: "jobscheduler-service",
+    installable: true,
+
+    srcs: [
+        "java/**/*.java",
+    ],
+
+    libs: [
+        "framework",
+        "services.core",
+    ],
+}
diff --git a/services/core/java/com/android/server/job/GrantedUriPermissions.java b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
similarity index 100%
rename from services/core/java/com/android/server/job/GrantedUriPermissions.java
rename to apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
diff --git a/services/core/java/com/android/server/job/JobCompletedListener.java b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
similarity index 100%
rename from services/core/java/com/android/server/job/JobCompletedListener.java
rename to apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
diff --git a/services/core/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
similarity index 100%
rename from services/core/java/com/android/server/job/JobConcurrencyManager.java
rename to apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
similarity index 100%
rename from services/core/java/com/android/server/job/JobPackageTracker.java
rename to apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
similarity index 88%
rename from services/core/java/com/android/server/job/JobSchedulerService.java
rename to apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index e44e902..38bb75f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -25,7 +25,6 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IUidObserver;
 import android.app.job.IJobScheduler;
@@ -95,7 +94,6 @@
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
-import com.android.server.job.JobSchedulerServiceDumpProto.RegisteredJob;
 import com.android.server.job.controllers.BackgroundJobsController;
 import com.android.server.job.controllers.BatteryController;
 import com.android.server.job.controllers.ConnectivityController;
@@ -117,7 +115,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -240,18 +237,7 @@
     final SparseIntArray mBackingUpUids = new SparseIntArray();
 
     /**
-     * Count standby heartbeats, and keep track of which beat each bucket's jobs will
-     * next become runnable.  Index into this array is by normalized bucket:
-     * { ACTIVE, WORKING, FREQUENT, RARE, NEVER }.  The ACTIVE and NEVER bucket
-     * milestones are not updated: ACTIVE apps get jobs whenever they ask for them,
-     * and NEVER apps don't get them at all.
-     */
-    final long[] mNextBucketHeartbeat = { 0, 0, 0, 0, Long.MAX_VALUE };
-    long mHeartbeat = 0;
-    long mLastHeartbeatTime = sElapsedRealtimeClock.millis();
-
-    /**
-     * Named indices into the STANDBY_BEATS array, for clarity in referring to
+     * Named indices into standby bucket arrays, for clarity in referring to
      * specific buckets' bookkeeping.
      */
     public static final int ACTIVE_INDEX = 0;
@@ -260,21 +246,6 @@
     public static final int RARE_INDEX = 3;
     public static final int NEVER_INDEX = 4;
 
-    /**
-     * Bookkeeping about when jobs last run.  We keep our own record in heartbeat time,
-     * rather than rely on Usage Stats' timestamps, because heartbeat time can be
-     * manipulated for testing purposes and we need job runnability to track that rather
-     * than real time.
-     *
-     * Outer SparseArray slices by user handle; inner map of package name to heartbeat
-     * is a HashMap<> rather than ArrayMap<> because we expect O(hundreds) of keys
-     * and it will be accessed in a known-hot code path.
-     */
-    final SparseArray<HashMap<String, Long>> mLastJobHeartbeats = new SparseArray<>();
-
-    static final String HEARTBEAT_TAG = "*job.heartbeat*";
-    final HeartbeatAlarmListener mHeartbeatAlarm = new HeartbeatAlarmListener();
-
     // -- Pre-allocated temporaries only for use in assignJobsToContextsLocked --
 
     private class ConstantsObserver extends ContentObserver {
@@ -311,11 +282,6 @@
                     Slog.e(TAG, "Bad jobscheduler settings", e);
                 }
             }
-
-            if (mConstants.USE_HEARTBEATS) {
-                // Reset the heartbeat alarm based on the new heartbeat duration
-                setNextHeartbeatAlarm();
-            }
         }
     }
 
@@ -465,13 +431,15 @@
         private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count";
         private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time";
         private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time";
-        private static final String KEY_STANDBY_HEARTBEAT_TIME = "standby_heartbeat_time";
-        private static final String KEY_STANDBY_WORKING_BEATS = "standby_working_beats";
-        private static final String KEY_STANDBY_FREQUENT_BEATS = "standby_frequent_beats";
-        private static final String KEY_STANDBY_RARE_BEATS = "standby_rare_beats";
+        private static final String DEPRECATED_KEY_STANDBY_HEARTBEAT_TIME =
+                "standby_heartbeat_time";
+        private static final String DEPRECATED_KEY_STANDBY_WORKING_BEATS = "standby_working_beats";
+        private static final String DEPRECATED_KEY_STANDBY_FREQUENT_BEATS =
+                "standby_frequent_beats";
+        private static final String DEPRECATED_KEY_STANDBY_RARE_BEATS = "standby_rare_beats";
         private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
         private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
-        private static final String KEY_USE_HEARTBEATS = "use_heartbeats";
+        private static final String DEPRECATED_KEY_USE_HEARTBEATS = "use_heartbeats";
 
         private static final int DEFAULT_MIN_IDLE_COUNT = 1;
         private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -488,13 +456,8 @@
         private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE;
         private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
         private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
-        private static final long DEFAULT_STANDBY_HEARTBEAT_TIME = 11 * 60 * 1000L;
-        private static final int DEFAULT_STANDBY_WORKING_BEATS = 11;  // ~ 2 hours, with 11min beats
-        private static final int DEFAULT_STANDBY_FREQUENT_BEATS = 43; // ~ 8 hours
-        private static final int DEFAULT_STANDBY_RARE_BEATS = 130; // ~ 24 hours
         private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
         private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
-        private static final boolean DEFAULT_USE_HEARTBEATS = false;
 
         /**
          * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -617,26 +580,7 @@
          * The minimum backoff time to allow for exponential backoff.
          */
         long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME;
-        /**
-         * How often we recalculate runnability based on apps' standby bucket assignment.
-         * This should be prime relative to common time interval lengths such as a quarter-
-         * hour or day, so that the heartbeat drifts relative to wall-clock milestones.
-         */
-        long STANDBY_HEARTBEAT_TIME = DEFAULT_STANDBY_HEARTBEAT_TIME;
-        /**
-         * Mapping: standby bucket -> number of heartbeats between each sweep of that
-         * bucket's jobs.
-         *
-         * Bucket assignments as recorded in the JobStatus objects are normalized to be
-         * indices into this array, rather than the raw constants used
-         * by AppIdleHistory.
-         */
-        final int[] STANDBY_BEATS = {
-                0,
-                DEFAULT_STANDBY_WORKING_BEATS,
-                DEFAULT_STANDBY_FREQUENT_BEATS,
-                DEFAULT_STANDBY_RARE_BEATS
-        };
+
         /**
          * The fraction of a job's running window that must pass before we
          * consider running it when the network is congested.
@@ -647,11 +591,6 @@
          * we consider matching it against a metered network.
          */
         public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC;
-        /**
-         * Whether to use heartbeats or rolling window for quota management. True will use
-         * heartbeats, false will use a rolling window.
-         */
-        public boolean USE_HEARTBEATS = DEFAULT_USE_HEARTBEATS;
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
@@ -709,19 +648,10 @@
                     DEFAULT_MIN_LINEAR_BACKOFF_TIME);
             MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME,
                     DEFAULT_MIN_EXP_BACKOFF_TIME);
-            STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME,
-                    DEFAULT_STANDBY_HEARTBEAT_TIME);
-            STANDBY_BEATS[WORKING_INDEX] = mParser.getInt(KEY_STANDBY_WORKING_BEATS,
-                    DEFAULT_STANDBY_WORKING_BEATS);
-            STANDBY_BEATS[FREQUENT_INDEX] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS,
-                    DEFAULT_STANDBY_FREQUENT_BEATS);
-            STANDBY_BEATS[RARE_INDEX] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
-                    DEFAULT_STANDBY_RARE_BEATS);
             CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC,
                     DEFAULT_CONN_CONGESTION_DELAY_FRAC);
             CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC,
                     DEFAULT_CONN_PREFETCH_RELAX_FRAC);
-            USE_HEARTBEATS = mParser.getBoolean(KEY_USE_HEARTBEATS, DEFAULT_USE_HEARTBEATS);
         }
 
         void dump(IndentingPrintWriter pw) {
@@ -757,17 +687,8 @@
             pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println();
             pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println();
             pw.printPair(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println();
-            pw.printPair(KEY_STANDBY_HEARTBEAT_TIME, STANDBY_HEARTBEAT_TIME).println();
-            pw.print("standby_beats={");
-            pw.print(STANDBY_BEATS[0]);
-            for (int i = 1; i < STANDBY_BEATS.length; i++) {
-                pw.print(", ");
-                pw.print(STANDBY_BEATS[i]);
-            }
-            pw.println('}');
             pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
             pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
-            pw.printPair(KEY_USE_HEARTBEATS, USE_HEARTBEATS).println();
 
             pw.decreaseIndent();
         }
@@ -797,13 +718,8 @@
             proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT);
             proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME);
             proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME);
-            proto.write(ConstantsProto.STANDBY_HEARTBEAT_TIME_MS, STANDBY_HEARTBEAT_TIME);
-            for (int period : STANDBY_BEATS) {
-                proto.write(ConstantsProto.STANDBY_BEATS, period);
-            }
             proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
             proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC);
-            proto.write(ConstantsProto.USE_HEARTBEATS, USE_HEARTBEATS);
         }
     }
 
@@ -1441,9 +1357,6 @@
 
             mAppStateTracker = Preconditions.checkNotNull(
                     LocalServices.getService(AppStateTracker.class));
-            if (mConstants.USE_HEARTBEATS) {
-                setNextHeartbeatAlarm();
-            }
 
             // Register br for package removals and user removals.
             final IntentFilter filter = new IntentFilter();
@@ -1647,7 +1560,7 @@
         }
         delayMillis =
                 Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
-        JobStatus newJob = new JobStatus(failureToReschedule, getCurrentHeartbeat(),
+        JobStatus newJob = new JobStatus(failureToReschedule,
                 elapsedNowMillis + delayMillis,
                 JobStatus.NO_LATEST_RUNTIME, backoffAttempts,
                 failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis());
@@ -1682,8 +1595,7 @@
      * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
      * to underscheduling at least, rather than if we had taken the last execution time to be the
      * start of the execution.
-     * <p>Unlike a reschedule prior to execution, in this case we advance the next-heartbeat
-     * tracking as though the job were newly-scheduled.
+     *
      * @return A new job representing the execution criteria for this instantiation of the
      * recurring job.
      */
@@ -1736,7 +1648,7 @@
         if (newLatestRuntimeElapsed < elapsedNow) {
             Slog.wtf(TAG, "Rescheduling calculated latest runtime in the past: "
                     + newLatestRuntimeElapsed);
-            return new JobStatus(periodicToReschedule, getCurrentHeartbeat(),
+            return new JobStatus(periodicToReschedule,
                     elapsedNow + period - flex, elapsedNow + period,
                     0 /* backoffAttempt */,
                     sSystemClock.millis() /* lastSuccessfulRunTime */,
@@ -1751,64 +1663,13 @@
                     newEarliestRunTimeElapsed / 1000 + ", " + newLatestRuntimeElapsed / 1000
                     + "]s");
         }
-        return new JobStatus(periodicToReschedule, getCurrentHeartbeat(),
+        return new JobStatus(periodicToReschedule,
                 newEarliestRunTimeElapsed, newLatestRuntimeElapsed,
                 0 /* backoffAttempt */,
                 sSystemClock.millis() /* lastSuccessfulRunTime */,
                 periodicToReschedule.getLastFailedRunTime());
     }
 
-    /*
-     * We default to "long enough ago that every bucket's jobs are immediately runnable" to
-     * avoid starvation of apps in uncommon-use buckets that might arise from repeated
-     * reboot behavior.
-     */
-    long heartbeatWhenJobsLastRun(String packageName, final @UserIdInt int userId) {
-        // The furthest back in pre-boot time that we need to bother with
-        long heartbeat = -mConstants.STANDBY_BEATS[RARE_INDEX];
-        boolean cacheHit = false;
-        synchronized (mLock) {
-            HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId);
-            if (jobPackages != null) {
-                long cachedValue = jobPackages.getOrDefault(packageName, Long.MAX_VALUE);
-                if (cachedValue < Long.MAX_VALUE) {
-                    cacheHit = true;
-                    heartbeat = cachedValue;
-                }
-            }
-            if (!cacheHit) {
-                // We haven't seen it yet; ask usage stats about it
-                final long timeSinceJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId);
-                if (timeSinceJob < Long.MAX_VALUE) {
-                    // Usage stats knows about it from before, so calculate back from that
-                    // and go from there.
-                    heartbeat = mHeartbeat - (timeSinceJob / mConstants.STANDBY_HEARTBEAT_TIME);
-                }
-                // If usage stats returned its "not found" MAX_VALUE, we still have the
-                // negative default 'heartbeat' value we established above
-                setLastJobHeartbeatLocked(packageName, userId, heartbeat);
-            }
-        }
-        if (DEBUG_STANDBY) {
-            Slog.v(TAG, "Last job heartbeat " + heartbeat + " for "
-                    + packageName + "/" + userId);
-        }
-        return heartbeat;
-    }
-
-    long heartbeatWhenJobsLastRun(JobStatus job) {
-        return heartbeatWhenJobsLastRun(job.getSourcePackageName(), job.getSourceUserId());
-    }
-
-    void setLastJobHeartbeatLocked(String packageName, int userId, long heartbeat) {
-        HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId);
-        if (jobPackages == null) {
-            jobPackages = new HashMap<>();
-            mLastJobHeartbeats.put(userId, jobPackages);
-        }
-        jobPackages.put(packageName, heartbeat);
-    }
-
     // JobCompletedListener implementations.
 
     /**
@@ -2176,82 +2037,6 @@
         mMaybeQueueFunctor.postProcess();
     }
 
-    /**
-     * Heartbeat tracking.  The heartbeat alarm is intentionally non-wakeup.
-     */
-    class HeartbeatAlarmListener implements AlarmManager.OnAlarmListener {
-
-        @Override
-        public void onAlarm() {
-            synchronized (mLock) {
-                final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime;
-                final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME;
-                if (beatsElapsed > 0) {
-                    mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME;
-                    advanceHeartbeatLocked(beatsElapsed);
-                }
-            }
-            setNextHeartbeatAlarm();
-        }
-    }
-
-    // Intentionally does not touch the alarm timing
-    void advanceHeartbeatLocked(long beatsElapsed) {
-        if (!mConstants.USE_HEARTBEATS) {
-            return;
-        }
-        mHeartbeat += beatsElapsed;
-        if (DEBUG_STANDBY) {
-            Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed
-                    + " to " + mHeartbeat);
-        }
-        // Don't update ACTIVE or NEVER bucket milestones.  Note that mHeartbeat
-        // will be equal to mNextBucketHeartbeat[bucket] for one beat, during which
-        // new jobs scheduled by apps in that bucket will be permitted to run
-        // immediately.
-        boolean didAdvanceBucket = false;
-        for (int i = 1; i < mNextBucketHeartbeat.length - 1; i++) {
-            // Did we reach or cross a bucket boundary?
-            if (mHeartbeat >= mNextBucketHeartbeat[i]) {
-                didAdvanceBucket = true;
-            }
-            while (mHeartbeat > mNextBucketHeartbeat[i]) {
-                mNextBucketHeartbeat[i] += mConstants.STANDBY_BEATS[i];
-            }
-            if (DEBUG_STANDBY) {
-                Slog.v(TAG, "   Bucket " + i + " next heartbeat "
-                        + mNextBucketHeartbeat[i]);
-            }
-        }
-
-        if (didAdvanceBucket) {
-            if (DEBUG_STANDBY) {
-                Slog.v(TAG, "Hit bucket boundary; reevaluating job runnability");
-            }
-            mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
-        }
-    }
-
-    void setNextHeartbeatAlarm() {
-        final long heartbeatLength;
-        synchronized (mLock) {
-            if (!mConstants.USE_HEARTBEATS) {
-                return;
-            }
-            heartbeatLength = mConstants.STANDBY_HEARTBEAT_TIME;
-        }
-        final long now = sElapsedRealtimeClock.millis();
-        final long nextBeatOrdinal = (now + heartbeatLength) / heartbeatLength;
-        final long nextHeartbeat = nextBeatOrdinal * heartbeatLength;
-        if (DEBUG_STANDBY) {
-            Slog.i(TAG, "Setting heartbeat alarm for " + nextHeartbeat
-                    + " = " + TimeUtils.formatDuration(nextHeartbeat - now));
-        }
-        AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
-        am.setExact(AlarmManager.ELAPSED_REALTIME, nextHeartbeat,
-                HEARTBEAT_TAG, mHeartbeatAlarm, mHandler);
-    }
-
     /** Returns true if both the calling and source users for the job are started. */
     private boolean areUsersStartedLocked(final JobStatus job) {
         boolean sourceStarted = ArrayUtils.contains(mStartedUsers, job.getSourceUserId());
@@ -2323,54 +2108,6 @@
             return false;
         }
 
-        if (mConstants.USE_HEARTBEATS) {
-            // If the app is in a non-active standby bucket, make sure we've waited
-            // an appropriate amount of time since the last invocation.  During device-
-            // wide parole, standby bucketing is ignored.
-            //
-            // Jobs in 'active' apps are not subject to standby, nor are jobs that are
-            // specifically marked as exempt.
-            if (DEBUG_STANDBY) {
-                Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
-                        + " parole=" + mInParole + " active=" + job.uidActive
-                        + " exempt=" + job.getJob().isExemptedFromAppStandby());
-            }
-            if (!mInParole
-                    && !job.uidActive
-                    && !job.getJob().isExemptedFromAppStandby()) {
-                final int bucket = job.getStandbyBucket();
-                if (DEBUG_STANDBY) {
-                    Slog.v(TAG, "  bucket=" + bucket + " heartbeat=" + mHeartbeat
-                            + " next=" + mNextBucketHeartbeat[bucket]);
-                }
-                if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
-                    // Only skip this job if the app is still waiting for the end of its nominal
-                    // bucket interval.  Once it's waited that long, we let it go ahead and clear.
-                    // The final (NEVER) bucket is special; we never age those apps' jobs into
-                    // runnability.
-                    final long appLastRan = heartbeatWhenJobsLastRun(job);
-                    if (bucket >= mConstants.STANDBY_BEATS.length
-                            || (mHeartbeat > appLastRan
-                            && mHeartbeat < appLastRan + mConstants.STANDBY_BEATS[bucket])) {
-                        if (job.getWhenStandbyDeferred() == 0) {
-                            if (DEBUG_STANDBY) {
-                                Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < "
-                                        + (appLastRan + mConstants.STANDBY_BEATS[bucket])
-                                        + " for " + job);
-                            }
-                            job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
-                        }
-                        return false;
-                    } else {
-                        if (DEBUG_STANDBY) {
-                            Slog.v(TAG, "Bucket deferred job aged into runnability at "
-                                    + mHeartbeat + " : " + job);
-                        }
-                    }
-                }
-            }
-        }
-
         // The expensive check: validate that the defined package+service is
         // still present & viable.
         return isComponentUsable(job);
@@ -2439,9 +2176,6 @@
 
         // Job pending/active doesn't affect the readiness of a job.
 
-        // Skipping the heartbeat check as this will only come into play when using the rolling
-        // window quota management system.
-
         // The expensive check: validate that the defined package+service is
         // still present & viable.
         return isComponentUsable(job);
@@ -2450,9 +2184,6 @@
     /** Returns the maximum amount of time this job could run for. */
     public long getMaxJobExecutionTimeMs(JobStatus job) {
         synchronized (mLock) {
-            if (mConstants.USE_HEARTBEATS) {
-                return JobServiceContext.EXECUTING_TIMESLICE_MILLIS;
-            }
             return Math.min(mQuotaController.getMaxJobExecutionTimeMsLocked(job),
                     JobServiceContext.EXECUTING_TIMESLICE_MILLIS);
         }
@@ -2498,56 +2229,6 @@
     final class LocalService implements JobSchedulerInternal {
 
         /**
-         * The current bucket heartbeat ordinal
-         */
-        public long currentHeartbeat() {
-            return getCurrentHeartbeat();
-        }
-
-        /**
-         * Heartbeat ordinal at which the given standby bucket's jobs next become runnable
-         */
-        public long nextHeartbeatForBucket(int bucket) {
-            synchronized (mLock) {
-                return mNextBucketHeartbeat[bucket];
-            }
-        }
-
-        /**
-         * Heartbeat ordinal for the given app.  This is typically the heartbeat at which
-         * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run
-         * jobs in a long time is immediately runnable even if the app is bucketed into
-         * an infrequent time allocation.
-         */
-        public long baseHeartbeatForApp(String packageName, @UserIdInt int userId,
-                final int appStandbyBucket) {
-            if (appStandbyBucket == 0 ||
-                    appStandbyBucket >= mConstants.STANDBY_BEATS.length) {
-                // ACTIVE => everything can be run right away
-                // NEVER => we won't run them anyway, so let them go in the future
-                // as soon as the app enters normal use
-                if (DEBUG_STANDBY) {
-                    Slog.v(TAG, "Base heartbeat forced ZERO for new job in "
-                            + packageName + "/" + userId);
-                }
-                return 0;
-            }
-
-            final long baseHeartbeat = heartbeatWhenJobsLastRun(packageName, userId);
-            if (DEBUG_STANDBY) {
-                Slog.v(TAG, "Base heartbeat " + baseHeartbeat + " for new job in "
-                        + packageName + "/" + userId);
-            }
-            return baseHeartbeat;
-        }
-
-        public void noteJobStart(String packageName, int userId) {
-            synchronized (mLock) {
-                setLastJobHeartbeatLocked(packageName, userId, mHeartbeat);
-            }
-        }
-
-        /**
          * Returns a list of all pending jobs. A running job is not considered pending. Periodic
          * jobs are always considered pending.
          */
@@ -3158,12 +2839,6 @@
         }
     }
 
-    long getCurrentHeartbeat() {
-        synchronized (mLock) {
-            return mHeartbeat;
-        }
-    }
-
     // Shell command infrastructure
     int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) {
         try {
@@ -3249,21 +2924,6 @@
         return 0;
     }
 
-    // Shell command infrastructure
-    int executeHeartbeatCommand(PrintWriter pw, int numBeats) {
-        if (numBeats < 1) {
-            pw.println(getCurrentHeartbeat());
-            return 0;
-        }
-
-        pw.print("Advancing standby heartbeat by ");
-        pw.println(numBeats);
-        synchronized (mLock) {
-            advanceHeartbeatLocked(numBeats);
-        }
-        return 0;
-    }
-
     void triggerDockState(boolean idleState) {
         final Intent dockIntent;
         if (idleState) {
@@ -3319,20 +2979,6 @@
             }
             pw.println();
 
-            pw.println("  Heartbeat:");
-            pw.print("    Current:    "); pw.println(mHeartbeat);
-            pw.println("    Next");
-            pw.print("      ACTIVE:   "); pw.println(mNextBucketHeartbeat[0]);
-            pw.print("      WORKING:  "); pw.println(mNextBucketHeartbeat[1]);
-            pw.print("      FREQUENT: "); pw.println(mNextBucketHeartbeat[2]);
-            pw.print("      RARE:     "); pw.println(mNextBucketHeartbeat[3]);
-            pw.print("    Last heartbeat: ");
-            TimeUtils.formatDuration(mLastHeartbeatTime, nowElapsed, pw);
-            pw.println();
-            pw.print("    Next heartbeat: ");
-            TimeUtils.formatDuration(mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME,
-                    nowElapsed, pw);
-            pw.println();
             pw.print("    In parole?: ");
             pw.print(mInParole);
             pw.println();
@@ -3358,9 +3004,6 @@
                     }
 
                     job.dump(pw, "    ", true, nowElapsed);
-                    pw.print("    Last run heartbeat: ");
-                    pw.print(heartbeatWhenJobsLastRun(job));
-                    pw.println();
 
                     pw.print("    Ready: ");
                     pw.print(isReadyToBeExecutedLocked(job));
@@ -3514,15 +3157,6 @@
             }
             proto.end(settingsToken);
 
-            proto.write(JobSchedulerServiceDumpProto.CURRENT_HEARTBEAT, mHeartbeat);
-            proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[0]);
-            proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[1]);
-            proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[2]);
-            proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[3]);
-            proto.write(JobSchedulerServiceDumpProto.LAST_HEARTBEAT_TIME_MILLIS,
-                    mLastHeartbeatTime - nowUptime);
-            proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT_TIME_MILLIS,
-                    mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME - nowUptime);
             proto.write(JobSchedulerServiceDumpProto.IN_PAROLE, mInParole);
             proto.write(JobSchedulerServiceDumpProto.IN_THERMAL, mThermalConstraint);
 
@@ -3564,7 +3198,6 @@
                     }
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_PRESENT,
                             componentPresent);
-                    proto.write(RegisteredJob.LAST_RUN_HEARTBEAT, heartbeatWhenJobsLastRun(job));
 
                     proto.end(rjToken);
                 }
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
similarity index 96%
rename from services/core/java/com/android/server/job/JobSchedulerShellCommand.java
rename to apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index e361441..01d158ba 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -340,15 +340,8 @@
     private int doHeartbeat(PrintWriter pw) throws Exception {
         checkPermission("manipulate scheduler heartbeat");
 
-        final String arg = getNextArg();
-        final int numBeats = (arg != null) ? Integer.parseInt(arg) : 0;
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            return mInternal.executeHeartbeatCommand(pw, numBeats);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
+        pw.println("Heartbeat command is no longer supported");
+        return -1;
     }
 
     private int triggerDockState(PrintWriter pw) throws Exception {
@@ -401,8 +394,7 @@
         pw.println("      -u or --user: specify which user's job is to be run; the default is");
         pw.println("         the primary or system user");
         pw.println("  heartbeat [num]");
-        pw.println("    With no argument, prints the current standby heartbeat.  With a positive");
-        pw.println("    argument, advances the standby heartbeat by that number.");
+        pw.println("    No longer used.");
         pw.println("  monitor-battery [on|off]");
         pw.println("    Control monitoring of all battery changes.  Off by default.  Turning");
         pw.println("    on makes get-battery-seq useful.");
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
similarity index 99%
rename from services/core/java/com/android/server/job/JobServiceContext.java
rename to apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 7da128f..4d9f133 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -285,9 +285,6 @@
             UsageStatsManagerInternal usageStats =
                     LocalServices.getService(UsageStatsManagerInternal.class);
             usageStats.setLastJobRunTime(jobPackage, jobUserId, mExecutionStartTimeElapsed);
-            JobSchedulerInternal jobScheduler =
-                    LocalServices.getService(JobSchedulerInternal.class);
-            jobScheduler.noteJobStart(jobPackage, jobUserId);
             mAvailable = false;
             mStoppedReason = null;
             mStoppedTime = 0;
diff --git a/services/core/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
similarity index 99%
rename from services/core/java/com/android/server/job/JobStore.java
rename to apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index d69faf3..4321fc7 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -189,7 +189,7 @@
             if (utcTimes != null) {
                 Pair<Long, Long> elapsedRuntimes =
                         convertRtcBoundsToElapsed(utcTimes, elapsedNow);
-                JobStatus newJob = new JobStatus(job, job.getBaseHeartbeat(),
+                JobStatus newJob = new JobStatus(job,
                         elapsedRuntimes.first, elapsedRuntimes.second,
                         0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime());
                 newJob.prepareLocked(am);
@@ -944,10 +944,9 @@
             JobSchedulerInternal service = LocalServices.getService(JobSchedulerInternal.class);
             final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName,
                     sourceUserId, elapsedNow);
-            long currentHeartbeat = service != null ? service.currentHeartbeat() : 0;
             JobStatus js = new JobStatus(
                     jobBuilder.build(), uid, sourcePackageName, sourceUserId,
-                    appBucket, currentHeartbeat, sourceTag,
+                    appBucket, sourceTag,
                     elapsedRuntimes.first, elapsedRuntimes.second,
                     lastSuccessfulRunTime, lastFailedRunTime,
                     (rtcIsGood) ? null : rtcRuntimes, internalFlags);
diff --git a/services/core/java/com/android/server/job/StateChangedListener.java b/apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java
similarity index 100%
rename from services/core/java/com/android/server/job/StateChangedListener.java
rename to apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/BatteryController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
similarity index 94%
rename from services/core/java/com/android/server/job/controllers/ConnectivityController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index f8cf6ae..a67aadf 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -47,7 +47,6 @@
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobSchedulerService.Constants;
-import com.android.server.job.JobServiceContext;
 import com.android.server.job.StateControllerProto;
 import com.android.server.net.NetworkPolicyManagerInternal;
 
@@ -88,8 +87,6 @@
     @GuardedBy("mLock")
     private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
 
-    private boolean mUseQuotaLimit;
-
     private static final int MSG_DATA_SAVER_TOGGLED = 0;
     private static final int MSG_UID_RULES_CHANGES = 1;
     private static final int MSG_REEVALUATE_JOBS = 2;
@@ -110,8 +107,6 @@
         mConnManager.registerNetworkCallback(request, mNetworkCallback);
 
         mNetPolicyManager.registerListener(mNetPolicyListener);
-
-        mUseQuotaLimit = !mConstants.USE_HEARTBEATS;
     }
 
     @GuardedBy("mLock")
@@ -142,24 +137,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    @Override
-    public void onConstantsUpdatedLocked() {
-        if (mConstants.USE_HEARTBEATS) {
-            // App idle exceptions are only requested for the rolling quota system.
-            if (DEBUG) Slog.i(TAG, "Revoking all standby exceptions");
-            for (int i = 0; i < mRequestedWhitelistJobs.size(); ++i) {
-                int uid = mRequestedWhitelistJobs.keyAt(i);
-                mNetPolicyManagerInternal.setAppIdleWhitelist(uid, false);
-            }
-            mRequestedWhitelistJobs.clear();
-        }
-        if (mUseQuotaLimit == mConstants.USE_HEARTBEATS) {
-            mUseQuotaLimit = !mConstants.USE_HEARTBEATS;
-            mHandler.obtainMessage(MSG_REEVALUATE_JOBS).sendToTarget();
-        }
-    }
-
     /**
      * Returns true if the job's requested network is available. This DOES NOT necesarilly mean
      * that the UID has been granted access to the network.
@@ -237,11 +214,6 @@
     @GuardedBy("mLock")
     @Override
     public void evaluateStateLocked(JobStatus jobStatus) {
-        if (mConstants.USE_HEARTBEATS) {
-            // This should only be used for the rolling quota system.
-            return;
-        }
-
         if (!jobStatus.hasConnectivityConstraint()) {
             return;
         }
@@ -263,9 +235,6 @@
     @GuardedBy("mLock")
     @Override
     public void reevaluateStateLocked(final int uid) {
-        if (mConstants.USE_HEARTBEATS) {
-            return;
-        }
         // Check if we still need a connectivity exception in case the JobService was disabled.
         ArraySet<JobStatus> jobs = mTrackedJobs.get(uid);
         if (jobs == null) {
@@ -329,9 +298,7 @@
      */
     private boolean isInsane(JobStatus jobStatus, Network network,
             NetworkCapabilities capabilities, Constants constants) {
-        final long maxJobExecutionTimeMs = mUseQuotaLimit
-                ? mService.getMaxJobExecutionTimeMs(jobStatus)
-                : JobServiceContext.EXECUTING_TIMESLICE_MILLIS;
+        final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus);
 
         final long downloadBytes = jobStatus.getEstimatedNetworkDownloadBytes();
         if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
@@ -617,7 +584,6 @@
     @Override
     public void dumpControllerStateLocked(IndentingPrintWriter pw,
             Predicate<JobStatus> predicate) {
-        pw.print("mUseQuotaLimit="); pw.println(mUseQuotaLimit);
 
         if (mRequestedWhitelistJobs.size() > 0) {
             pw.print("Requested standby exceptions:");
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/ContentObserverController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/IdleController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
similarity index 98%
rename from services/core/java/com/android/server/job/controllers/JobStatus.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 6f2b334..ae4abd6 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -169,12 +169,6 @@
     private final int numFailures;
 
     /**
-     * Current standby heartbeat when this job was scheduled or last ran.  Used to
-     * pin the runnability check regardless of the job's app moving between buckets.
-     */
-    private final long baseHeartbeat;
-
-    /**
      * Which app standby bucket this job's app is in.  Updated when the app is moved to a
      * different bucket.
      */
@@ -350,8 +344,6 @@
      * @param standbyBucket The standby bucket that the source package is currently assigned to,
      *     cached here for speed of handling during runnability evaluations (and updated when bucket
      *     assignments are changed)
-     * @param heartbeat Timestamp of when the job was created, in the standby-related
-     *     timebase.
      * @param tag A string associated with the job for debugging/logging purposes.
      * @param numFailures Count of how many times this job has requested a reschedule because
      *     its work was not yet finished.
@@ -364,13 +356,12 @@
      * @param internalFlags Non-API property flags about this job
      */
     private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
-            int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures,
+            int sourceUserId, int standbyBucket, String tag, int numFailures,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
             long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) {
         this.job = job;
         this.callingUid = callingUid;
         this.standbyBucket = standbyBucket;
-        this.baseHeartbeat = heartbeat;
 
         int tempSourceUid = -1;
         if (sourceUserId != -1 && sourcePackageName != null) {
@@ -440,7 +431,7 @@
     public JobStatus(JobStatus jobStatus) {
         this(jobStatus.getJob(), jobStatus.getUid(),
                 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
-                jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(),
+                jobStatus.getStandbyBucket(),
                 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
                 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
                 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
@@ -462,13 +453,13 @@
      * standby bucket is whatever the OS thinks it should be at this moment.
      */
     public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId,
-            int standbyBucket, long baseHeartbeat, String sourceTag,
+            int standbyBucket, String sourceTag,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
             long lastSuccessfulRunTime, long lastFailedRunTime,
             Pair<Long, Long> persistedExecutionTimesUTC,
             int innerFlags) {
         this(job, callingUid, sourcePkgName, sourceUserId,
-                standbyBucket, baseHeartbeat,
+                standbyBucket,
                 sourceTag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
                 lastSuccessfulRunTime, lastFailedRunTime, innerFlags);
@@ -486,13 +477,13 @@
     }
 
     /** Create a new job to be rescheduled with the provided parameters. */
-    public JobStatus(JobStatus rescheduling, long newBaseHeartbeat,
+    public JobStatus(JobStatus rescheduling,
             long newEarliestRuntimeElapsedMillis,
             long newLatestRuntimeElapsedMillis, int backoffAttempt,
             long lastSuccessfulRunTime, long lastFailedRunTime) {
         this(rescheduling.job, rescheduling.getUid(),
                 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
-                rescheduling.getStandbyBucket(), newBaseHeartbeat,
+                rescheduling.getStandbyBucket(),
                 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
                 newLatestRuntimeElapsedMillis,
                 lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags());
@@ -529,11 +520,8 @@
         int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
                 sourceUserId, elapsedNow);
         JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
-        long currentHeartbeat = js != null
-                ? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket)
-                : 0;
         return new JobStatus(job, callingUid, sourcePkg, sourceUserId,
-                standbyBucket, currentHeartbeat, tag, 0,
+                standbyBucket, tag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
                 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
                 /*innerFlags=*/ 0);
@@ -714,10 +702,6 @@
         return standbyBucket;
     }
 
-    public long getBaseHeartbeat() {
-        return baseHeartbeat;
-    }
-
     public void setStandbyBucket(int newBucket) {
         standbyBucket = newBucket;
     }
@@ -1631,10 +1615,6 @@
         }
         pw.print(prefix); pw.print("Standby bucket: ");
         pw.println(getBucketName());
-        if (standbyBucket > 0) {
-            pw.print(prefix); pw.print("Base heartbeat: ");
-            pw.println(baseHeartbeat);
-        }
         if (whenStandbyDeferred != 0) {
             pw.print(prefix); pw.print("  Deferred since: ");
             TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
similarity index 98%
rename from services/core/java/com/android/server/job/controllers/QuotaController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index b8cfac4..043cda4 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -416,13 +416,6 @@
 
     private volatile boolean mInParole;
 
-    /**
-     * If the QuotaController should throttle apps based on their standby bucket and job activity.
-     * If false, all jobs will have their CONSTRAINT_WITHIN_QUOTA bit set to true immediately and
-     * indefinitely.
-     */
-    private boolean mShouldThrottle;
-
     /** How much time each app will have to run jobs within their standby bucket window. */
     private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
 
@@ -594,8 +587,6 @@
         } catch (RemoteException e) {
             // ignored; both services live in system_server
         }
-
-        mShouldThrottle = !mConstants.USE_HEARTBEATS;
     }
 
     @Override
@@ -607,8 +598,6 @@
     public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
         final int userId = jobStatus.getSourceUserId();
         final String pkgName = jobStatus.getSourcePackageName();
-        // Still need to track jobs even if mShouldThrottle is false in case it's set to true at
-        // some point.
         ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
         if (jobs == null) {
             jobs = new ArraySet<>();
@@ -616,16 +605,10 @@
         }
         jobs.add(jobStatus);
         jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA);
-        if (mShouldThrottle) {
-            final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
-            setConstraintSatisfied(jobStatus, isWithinQuota);
-            if (!isWithinQuota) {
-                maybeScheduleStartAlarmLocked(userId, pkgName,
-                        getEffectiveStandbyBucket(jobStatus));
-            }
-        } else {
-            // QuotaController isn't throttling, so always set to true.
-            jobStatus.setQuotaConstraintSatisfied(true);
+        final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
+        setConstraintSatisfied(jobStatus, isWithinQuota);
+        if (!isWithinQuota) {
+            maybeScheduleStartAlarmLocked(userId, pkgName, getEffectiveStandbyBucket(jobStatus));
         }
     }
 
@@ -674,20 +657,6 @@
     }
 
     @Override
-    public void onConstantsUpdatedLocked() {
-        if (mShouldThrottle == mConstants.USE_HEARTBEATS) {
-            mShouldThrottle = !mConstants.USE_HEARTBEATS;
-
-            // Update job bookkeeping out of band.
-            BackgroundThread.getHandler().post(() -> {
-                synchronized (mLock) {
-                    maybeUpdateAllConstraintsLocked();
-                }
-            });
-        }
-    }
-
-    @Override
     public void onAppRemovedLocked(String packageName, int uid) {
         if (packageName == null) {
             Slog.wtf(TAG, "Told app removed but given null package name.");
@@ -780,8 +749,6 @@
     boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
             final int standbyBucket) {
         if (standbyBucket == NEVER_INDEX) return false;
-        // This check is needed in case the flag is toggled after a job has been registered.
-        if (!mShouldThrottle) return true;
 
         // Quota constraint is not enforced while charging or when parole is on.
         if (mChargeTracker.isCharging() || mInParole) {
@@ -1820,8 +1787,7 @@
                     if (timer != null && timer.isActive()) {
                         timer.rescheduleCutoff();
                     }
-                    if (!mShouldThrottle || maybeUpdateConstraintForPkgLocked(userId,
-                            packageName)) {
+                    if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
                         mStateChangedListener.onControllerStateChanged();
                     }
                 }
@@ -2396,7 +2362,7 @@
                     changed = true;
                 }
 
-                if (changed && mShouldThrottle) {
+                if (changed) {
                     // Update job bookkeeping out of band.
                     BackgroundThread.getHandler().post(() -> {
                         synchronized (mLock) {
@@ -2561,7 +2527,6 @@
     @Override
     public void dumpControllerStateLocked(final IndentingPrintWriter pw,
             final Predicate<JobStatus> predicate) {
-        pw.println("Is throttling: " + mShouldThrottle);
         pw.println("Is charging: " + mChargeTracker.isCharging());
         pw.println("In parole: " + mInParole);
         pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis());
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/StateController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/StorageController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/TimeController.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
diff --git a/services/core/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
diff --git a/services/core/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
diff --git a/services/core/java/com/android/server/job/controllers/idle/IdlenessListener.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessListener.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/idle/IdlenessListener.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessListener.java
diff --git a/services/core/java/com/android/server/job/controllers/idle/IdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
similarity index 100%
rename from services/core/java/com/android/server/job/controllers/idle/IdlenessTracker.java
rename to apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
diff --git a/api/current.txt b/api/current.txt
index aa772f1..afacaa8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -103,6 +103,7 @@
     field public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
     field @Deprecated public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
+    field public static final String QUERY_ALL_PACKAGES = "android.permission.QUERY_ALL_PACKAGES";
     field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
     field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
     field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
@@ -7176,6 +7177,7 @@
     method public android.os.Bundle getExtras();
     method public int getHeight();
     method public String getHint();
+    method @Nullable public String getHintIdEntry();
     method @Nullable public android.view.ViewStructure.HtmlInfo getHtmlInfo();
     method public int getId();
     method public String getIdEntry();
@@ -29828,6 +29830,7 @@
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
     method public int getMaxNumberOfNetworkSuggestionsPerApp();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) @NonNull public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
     method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
@@ -51452,6 +51455,7 @@
     method public abstract void setFocusable(boolean);
     method public abstract void setFocused(boolean);
     method public abstract void setHint(CharSequence);
+    method public void setHintIdEntry(@NonNull String);
     method public abstract void setHtmlInfo(@NonNull android.view.ViewStructure.HtmlInfo);
     method public abstract void setId(int, String, String, String);
     method public void setImportantForAutofill(int);
@@ -57003,66 +57007,66 @@
     method public void setTrackTintMode(@Nullable android.graphics.PorterDuff.Mode);
   }
 
-  public class TabHost extends android.widget.FrameLayout implements android.view.ViewTreeObserver.OnTouchModeChangeListener {
-    ctor public TabHost(android.content.Context);
-    ctor public TabHost(android.content.Context, android.util.AttributeSet);
-    ctor public TabHost(android.content.Context, android.util.AttributeSet, int);
-    ctor public TabHost(android.content.Context, android.util.AttributeSet, int, int);
-    method public void addTab(android.widget.TabHost.TabSpec);
-    method public void clearAllTabs();
-    method @Nullable public int getCurrentTab();
-    method @Nullable public String getCurrentTabTag();
-    method @Nullable public android.view.View getCurrentTabView();
-    method public android.view.View getCurrentView();
-    method public android.widget.FrameLayout getTabContentView();
-    method public android.widget.TabWidget getTabWidget();
-    method @NonNull public android.widget.TabHost.TabSpec newTabSpec(@NonNull String);
-    method public void onTouchModeChanged(boolean);
-    method public void setCurrentTab(int);
-    method public void setCurrentTabByTag(String);
-    method public void setOnTabChangedListener(android.widget.TabHost.OnTabChangeListener);
-    method public void setup();
-    method public void setup(android.app.LocalActivityManager);
+  @Deprecated public class TabHost extends android.widget.FrameLayout implements android.view.ViewTreeObserver.OnTouchModeChangeListener {
+    ctor @Deprecated public TabHost(android.content.Context);
+    ctor @Deprecated public TabHost(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public TabHost(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public TabHost(android.content.Context, android.util.AttributeSet, int, int);
+    method @Deprecated public void addTab(android.widget.TabHost.TabSpec);
+    method @Deprecated public void clearAllTabs();
+    method @Deprecated @Nullable public int getCurrentTab();
+    method @Deprecated @Nullable public String getCurrentTabTag();
+    method @Deprecated @Nullable public android.view.View getCurrentTabView();
+    method @Deprecated public android.view.View getCurrentView();
+    method @Deprecated public android.widget.FrameLayout getTabContentView();
+    method @Deprecated public android.widget.TabWidget getTabWidget();
+    method @Deprecated @NonNull public android.widget.TabHost.TabSpec newTabSpec(@NonNull String);
+    method @Deprecated public void onTouchModeChanged(boolean);
+    method @Deprecated public void setCurrentTab(int);
+    method @Deprecated public void setCurrentTabByTag(String);
+    method @Deprecated public void setOnTabChangedListener(android.widget.TabHost.OnTabChangeListener);
+    method @Deprecated public void setup();
+    method @Deprecated public void setup(android.app.LocalActivityManager);
   }
 
-  public static interface TabHost.OnTabChangeListener {
-    method public void onTabChanged(String);
+  @Deprecated public static interface TabHost.OnTabChangeListener {
+    method @Deprecated public void onTabChanged(String);
   }
 
-  public static interface TabHost.TabContentFactory {
-    method public android.view.View createTabContent(String);
+  @Deprecated public static interface TabHost.TabContentFactory {
+    method @Deprecated public android.view.View createTabContent(String);
   }
 
-  public class TabHost.TabSpec {
-    method @NonNull public String getTag();
-    method public android.widget.TabHost.TabSpec setContent(int);
-    method public android.widget.TabHost.TabSpec setContent(android.widget.TabHost.TabContentFactory);
-    method public android.widget.TabHost.TabSpec setContent(android.content.Intent);
-    method public android.widget.TabHost.TabSpec setIndicator(CharSequence);
-    method public android.widget.TabHost.TabSpec setIndicator(CharSequence, android.graphics.drawable.Drawable);
-    method public android.widget.TabHost.TabSpec setIndicator(android.view.View);
+  @Deprecated public class TabHost.TabSpec {
+    method @Deprecated @NonNull public String getTag();
+    method @Deprecated public android.widget.TabHost.TabSpec setContent(int);
+    method @Deprecated public android.widget.TabHost.TabSpec setContent(android.widget.TabHost.TabContentFactory);
+    method @Deprecated public android.widget.TabHost.TabSpec setContent(android.content.Intent);
+    method @Deprecated public android.widget.TabHost.TabSpec setIndicator(CharSequence);
+    method @Deprecated public android.widget.TabHost.TabSpec setIndicator(CharSequence, android.graphics.drawable.Drawable);
+    method @Deprecated public android.widget.TabHost.TabSpec setIndicator(android.view.View);
   }
 
-  public class TabWidget extends android.widget.LinearLayout implements android.view.View.OnFocusChangeListener {
-    ctor public TabWidget(android.content.Context);
-    ctor public TabWidget(android.content.Context, android.util.AttributeSet);
-    ctor public TabWidget(android.content.Context, android.util.AttributeSet, int);
-    ctor public TabWidget(android.content.Context, android.util.AttributeSet, int, int);
-    method public void dispatchDraw(android.graphics.Canvas);
-    method public void focusCurrentTab(int);
-    method public android.view.View getChildTabViewAt(int);
-    method @Nullable public android.graphics.drawable.Drawable getLeftStripDrawable();
-    method @Nullable public android.graphics.drawable.Drawable getRightStripDrawable();
-    method public int getTabCount();
-    method public boolean isStripEnabled();
-    method public void onFocusChange(android.view.View, boolean);
-    method public void setCurrentTab(int);
-    method public void setDividerDrawable(@DrawableRes int);
-    method public void setLeftStripDrawable(@Nullable android.graphics.drawable.Drawable);
-    method public void setLeftStripDrawable(@DrawableRes int);
-    method public void setRightStripDrawable(@Nullable android.graphics.drawable.Drawable);
-    method public void setRightStripDrawable(@DrawableRes int);
-    method public void setStripEnabled(boolean);
+  @Deprecated public class TabWidget extends android.widget.LinearLayout implements android.view.View.OnFocusChangeListener {
+    ctor @Deprecated public TabWidget(android.content.Context);
+    ctor @Deprecated public TabWidget(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public TabWidget(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public TabWidget(android.content.Context, android.util.AttributeSet, int, int);
+    method @Deprecated public void dispatchDraw(android.graphics.Canvas);
+    method @Deprecated public void focusCurrentTab(int);
+    method @Deprecated public android.view.View getChildTabViewAt(int);
+    method @Deprecated @Nullable public android.graphics.drawable.Drawable getLeftStripDrawable();
+    method @Deprecated @Nullable public android.graphics.drawable.Drawable getRightStripDrawable();
+    method @Deprecated public int getTabCount();
+    method @Deprecated public boolean isStripEnabled();
+    method @Deprecated public void onFocusChange(android.view.View, boolean);
+    method @Deprecated public void setCurrentTab(int);
+    method @Deprecated public void setDividerDrawable(@DrawableRes int);
+    method @Deprecated public void setLeftStripDrawable(@Nullable android.graphics.drawable.Drawable);
+    method @Deprecated public void setLeftStripDrawable(@DrawableRes int);
+    method @Deprecated public void setRightStripDrawable(@Nullable android.graphics.drawable.Drawable);
+    method @Deprecated public void setRightStripDrawable(@DrawableRes int);
+    method @Deprecated public void setStripEnabled(boolean);
   }
 
   public class TableLayout extends android.widget.LinearLayout {
diff --git a/api/system-current.txt b/api/system-current.txt
index eef6b3f..15b694a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9095,6 +9095,7 @@
   public abstract class ImsFeature {
     ctor public ImsFeature();
     method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+    method public final int getSlotIndex();
     method public abstract void onFeatureReady();
     method public abstract void onFeatureRemoved();
     method public final void setFeatureState(int);
@@ -9108,7 +9109,7 @@
     field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
-  @Deprecated public static class ImsFeature.Capabilities {
+  public static class ImsFeature.Capabilities {
     field @Deprecated protected int mCapabilities;
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 8e6ff30..46a0e1b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2869,6 +2869,11 @@
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int);
   }
 
+  public class PhoneNumberUtils {
+    method public static int getMinMatchForTest();
+    method public static void setMinMatchForTest(int);
+  }
+
   public class ServiceState implements android.os.Parcelable {
     method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
     method public void setCdmaSystemAndNetworkId(int, int);
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index c1f8654..3e5877b 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -40,27 +40,6 @@
         "audioplay.cpp",
     ],
 
-    product_variables: {
-        product_is_iot: {
-            shared_libs: [
-                "libandroidthings",
-                "libandroidthings_protos",
-                "libchrome",
-                "libprotobuf-cpp-lite",
-            ],
-            static_libs: ["libjsoncpp"],
-            srcs: [
-                "iot/iotbootanimation_main.cpp",
-                "iot/BootAction.cpp",
-                "iot/BootParameters.cpp",
-            ],
-            exclude_srcs: [
-                "bootanimation_main.cpp",
-                "audioplay.cpp",
-            ],
-        },
-    },
-
     init_rc: ["bootanim.rc"],
 }
 
@@ -80,10 +59,4 @@
         "libGLESv1_CM",
         "libgui",
     ],
-
-    product_variables: {
-        product_is_iot: {
-            init_rc: ["iot/bootanim_iot.rc"],
-        },
-    },
 }
diff --git a/cmds/bootanimation/iot/Android.bp b/cmds/bootanimation/iot/Android.bp
deleted file mode 100644
index 1f248ad..0000000
--- a/cmds/bootanimation/iot/Android.bp
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-// libbootanimation_iot_test
-// ===========================================================
-cc_test {
-    name: "libbootanimation_iot_test",
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wunused",
-        "-Wunreachable-code",
-    ],
-
-    shared_libs: [
-        "libandroidthings",
-        "libandroidthings_protos",
-        "libbase",
-        "libchrome",
-        "liblog",
-        "libprotobuf-cpp-lite",
-    ],
-
-    static_libs: ["libjsoncpp"],
-
-    srcs: [
-        "BootParameters.cpp",
-        "BootParameters_test.cpp",
-    ],
-
-    enabled: false,
-    product_variables: {
-        product_is_iot: {
-            enabled: true,
-        },
-    },
-}
diff --git a/cmds/bootanimation/iot/BootAction.cpp b/cmds/bootanimation/iot/BootAction.cpp
deleted file mode 100644
index 8b55147..0000000
--- a/cmds/bootanimation/iot/BootAction.cpp
+++ /dev/null
@@ -1,132 +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.
- */
-
-#include "BootAction.h"
-
-#define LOG_TAG "BootAction"
-
-#include <dlfcn.h>
-
-#include <pio/peripheral_manager_client.h>
-#include <utils/Log.h>
-
-namespace android {
-
-BootAction::~BootAction() {
-    if (mLibHandle != nullptr) {
-        dlclose(mLibHandle);
-    }
-}
-
-bool BootAction::init(const std::string& libraryPath,
-                      const std::unique_ptr<BootParameters>& bootParameters) {
-    APeripheralManagerClient* client = nullptr;
-    ALOGD("Connecting to peripheralmanager");
-    // Wait for peripheral manager to come up.
-    while (client == nullptr) {
-        client = APeripheralManagerClient_new();
-        if (client == nullptr) {
-          ALOGV("peripheralmanager is not up, sleeping before we check again.");
-          usleep(250000);
-        }
-    }
-    ALOGD("Peripheralmanager is up.");
-    APeripheralManagerClient_delete(client);
-
-
-    ALOGI("Loading boot action %s", libraryPath.c_str());
-    mLibHandle = dlopen(libraryPath.c_str(), RTLD_NOW);
-    if (mLibHandle == nullptr) {
-        ALOGE("Unable to load library at %s :: %s",
-              libraryPath.c_str(), dlerror());
-        return false;
-    }
-
-    void* loaded = nullptr;
-    if (!loadSymbol("boot_action_init", &loaded) || loaded == nullptr) {
-        return false;
-    }
-    mLibInit = reinterpret_cast<libInit>(loaded);
-
-    loaded = nullptr;
-    if (!loadSymbol("boot_action_shutdown", &loaded) || loaded == nullptr) {
-        return false;
-    }
-    mLibShutdown = reinterpret_cast<libShutdown>(loaded);
-
-    // StartPart is considered optional, if it isn't exported by the library
-    // we will still call init and shutdown.
-    loaded = nullptr;
-    if (!loadSymbol("boot_action_start_part", &loaded) || loaded == nullptr) {
-        ALOGI("No boot_action_start_part found, action will not be told when "
-              "Animation parts change.");
-    } else {
-        mLibStartPart = reinterpret_cast<libStartPart>(loaded);
-    }
-
-    // SilentBoot is considered optional, if it isn't exported by the library
-    // and the boot is silent, no method is called.
-    loaded = nullptr;
-    if (!loadSymbol("boot_action_silent_boot", &loaded) || loaded == nullptr) {
-        ALOGW("No boot_action_silent_boot found, boot action will not be "
-              "executed during a silent boot.");
-    } else {
-        mLibSilentBoot = reinterpret_cast<libInit>(loaded);
-    }
-
-    bool result = true;
-    const auto& parameters = bootParameters->getParameters();
-    if (bootParameters->isSilentBoot()) {
-        if (mLibSilentBoot != nullptr) {
-            ALOGD("Entering boot_action_silent_boot");
-            result = mLibSilentBoot(parameters.data(), parameters.size());
-            ALOGD("Returned from boot_action_silent_boot");
-        } else {
-            ALOGW("Skipping missing boot_action_silent_boot");
-        }
-    } else {
-        ALOGD("Entering boot_action_init");
-        result = mLibInit(parameters.data(), parameters.size());
-        ALOGD("Returned from boot_action_init");
-    }
-
-    return result;
-}
-
-void BootAction::startPart(int partNumber, int playNumber) {
-    if (mLibStartPart == nullptr) return;
-
-    ALOGD("Entering boot_action_start_part");
-    mLibStartPart(partNumber, playNumber);
-    ALOGD("Returned from boot_action_start_part");
-}
-
-void BootAction::shutdown() {
-    ALOGD("Entering boot_action_shutdown");
-    mLibShutdown();
-    ALOGD("Returned from boot_action_shutdown");
-}
-
-bool BootAction::loadSymbol(const char* symbol, void** loaded) {
-    *loaded = dlsym(mLibHandle, symbol);
-    if (*loaded == nullptr) {
-        ALOGE("Unable to load symbol : %s :: %s", symbol, dlerror());
-        return false;
-    }
-    return true;
-}
-
-}  // namespace android
diff --git a/cmds/bootanimation/iot/BootAction.h b/cmds/bootanimation/iot/BootAction.h
deleted file mode 100644
index 7119c35..0000000
--- a/cmds/bootanimation/iot/BootAction.h
+++ /dev/null
@@ -1,68 +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.
- */
-
-#ifndef _BOOTANIMATION_BOOTACTION_H
-#define _BOOTANIMATION_BOOTACTION_H
-
-#include <string>
-#include <vector>
-
-#include "BootParameters.h"
-
-#include <boot_action/boot_action.h>  // libandroidthings native API.
-#include <utils/RefBase.h>
-
-namespace android {
-
-class BootAction : public RefBase {
-public:
-    ~BootAction();
-
-    // libraryPath is a fully qualified path to the target .so library.
-    bool init(const std::string& libraryPath,
-              const std::unique_ptr<BootParameters>& bootParameters);
-
-    // The animation is going to start playing partNumber for the playCount'th
-    // time, update the action as needed.
-    // This is run in the same thread as the boot animation,
-    // you must not block here.
-    void startPart(int partNumber, int playCount);
-
-    // Shutdown the boot action, this will be called shortly before the
-    // process is shut down to allow time for cleanup.
-    void shutdown();
-
-private:
-    typedef bool (*libInit)(const ABootActionParameter* parameters,
-                            size_t numParameters);
-    typedef void (*libStartPart)(int partNumber, int playNumber);
-    typedef void (*libShutdown)();
-
-    bool loadSymbol(const char* symbol, void** loaded);
-
-    void* mLibHandle = nullptr;
-    libInit mLibInit = nullptr;
-    libStartPart mLibStartPart = nullptr;
-    libShutdown mLibShutdown = nullptr;
-
-    // Called only if the boot is silent.
-    libInit mLibSilentBoot = nullptr;
-};
-
-}  // namespace android
-
-
-#endif  // _BOOTANIMATION_BOOTACTION_H
diff --git a/cmds/bootanimation/iot/BootParameters.cpp b/cmds/bootanimation/iot/BootParameters.cpp
deleted file mode 100644
index 30a9b28..0000000
--- a/cmds/bootanimation/iot/BootParameters.cpp
+++ /dev/null
@@ -1,197 +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.
- */
-
-#include "BootParameters.h"
-
-#define LOG_TAG "BootParameters"
-
-#include <errno.h>
-#include <fcntl.h>
-
-#include <android-base/file.h>
-#include <json/json.h>
-#include <utils/Log.h>
-
-using android::base::ReadFileToString;
-using android::base::RemoveFileIfExists;
-using android::base::WriteStringToFile;
-using Json::ArrayIndex;
-using Json::Reader;
-using Json::Value;
-
-namespace android {
-
-namespace {
-
-// Keys for deprecated parameters. Devices that OTA from N to O and that used
-// the hidden BootParameters API will store these in the JSON blob. To support
-// the transition from N to O, these keys are mapped to the new parameters.
-constexpr const char *kKeyLegacyVolume = "volume";
-constexpr const char *kKeyLegacyAnimationsDisabled = "boot_animation_disabled";
-constexpr const char *kKeyLegacyParamNames = "param_names";
-constexpr const char *kKeyLegacyParamValues = "param_values";
-
-constexpr const char *kNextBootFile = "/data/misc/bootanimation/next_boot.proto";
-constexpr const char *kLastBootFile = "/data/misc/bootanimation/last_boot.proto";
-
-constexpr const char *kLegacyNextBootFile = "/data/misc/bootanimation/next_boot.json";
-constexpr const char *kLegacyLastBootFile = "/data/misc/bootanimation/last_boot.json";
-
-void removeLegacyFiles() {
-    std::string err;
-    if (!RemoveFileIfExists(kLegacyLastBootFile, &err)) {
-        ALOGW("Unable to delete %s: %s", kLegacyLastBootFile, err.c_str());
-    }
-
-    err.clear();
-    if (!RemoveFileIfExists(kLegacyNextBootFile, &err)) {
-        ALOGW("Unable to delete %s: %s", kLegacyNextBootFile, err.c_str());
-    }
-}
-
-void createNextBootFile() {
-    errno = 0;
-    int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE);
-    if (fd == -1) {
-        ALOGE("Unable to create next boot file: %s", strerror(errno));
-    } else {
-        // Make next_boot.json writable to everyone so DeviceManagementService
-        // can save saved_parameters there.
-        if (fchmod(fd, DEFFILEMODE))
-            ALOGE("Unable to set next boot file permissions: %s", strerror(errno));
-        close(fd);
-    }
-}
-
-}  // namespace
-
-// Renames the 'next' boot file to the 'last' file and reads its contents.
-bool BootParameters::swapAndLoadBootConfigContents(const char *lastBootFile,
-                                                   const char *nextBootFile,
-                                                   std::string *contents) {
-    if (!ReadFileToString(nextBootFile, contents)) {
-        RemoveFileIfExists(lastBootFile);
-        return false;
-    }
-
-    errno = 0;
-    if (rename(nextBootFile, lastBootFile) && errno != ENOENT)
-        ALOGE("Unable to swap boot files: %s", strerror(errno));
-
-    return true;
-}
-
-BootParameters::BootParameters() {
-    loadParameters();
-}
-
-// Saves the boot parameters state to disk so the framework can read it.
-void BootParameters::storeParameters() {
-    errno = 0;
-    if (!WriteStringToFile(mProto.SerializeAsString(), kLastBootFile)) {
-        ALOGE("Failed to write boot parameters to %s: %s", kLastBootFile, strerror(errno));
-    }
-
-    // WriteStringToFile sets the file permissions to 0666, but these are not
-    // honored by the system.
-    errno = 0;
-    if (chmod(kLastBootFile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) {
-        ALOGE("Failed to set permissions for %s: %s", kLastBootFile, strerror(errno));
-    }
-}
-
-// Load the boot parameters from disk, try the old location and format if the
-// file does not exist. Note:
-// - Parse errors result in defaults being used (a normal boot).
-// - Legacy boot parameters default to a silent boot.
-void BootParameters::loadParameters() {
-    // Precedence is given to the new file format (.proto).
-    std::string contents;
-    if (swapAndLoadBootConfigContents(kLastBootFile, kNextBootFile, &contents)) {
-        parseBootParameters(contents);
-    } else if (swapAndLoadBootConfigContents(kLegacyLastBootFile, kLegacyNextBootFile, &contents)) {
-        parseLegacyBootParameters(contents);
-        storeParameters();
-        removeLegacyFiles();
-    }
-
-    createNextBootFile();
-}
-
-void BootParameters::parseBootParameters(const std::string &contents) {
-    if (!mProto.ParseFromString(contents)) {
-        ALOGW("Failed to parse parameters from %s", kLastBootFile);
-        return;
-    }
-
-    loadStateFromProto();
-}
-
-// Parses the JSON in the proto.
-void BootParameters::parseLegacyBootParameters(const std::string &contents) {
-    Value json;
-    if (!Reader().parse(contents, json)) {
-        ALOGW("Failed to parse parameters from %s", kLegacyLastBootFile);
-        return;
-    }
-
-    int volume = 0;
-    bool bootAnimationDisabled = true;
-
-    Value &jsonValue = json[kKeyLegacyVolume];
-    if (jsonValue.isIntegral()) {
-        volume = jsonValue.asInt();
-    }
-
-    jsonValue = json[kKeyLegacyAnimationsDisabled];
-    if (jsonValue.isIntegral()) {
-        bootAnimationDisabled = jsonValue.asInt() == 1;
-    }
-
-    // Assume a silent boot unless all of the following are true -
-    // 1. The volume is neither 0 nor -1000 (the legacy default value).
-    // 2. The boot animations are explicitly enabled.
-    // Note: brightness was never used.
-    mProto.set_silent_boot((volume == 0) || (volume == -1000) || bootAnimationDisabled);
-
-    Value &keys = json[kKeyLegacyParamNames];
-    Value &values = json[kKeyLegacyParamValues];
-    if (keys.isArray() && values.isArray() && (keys.size() == values.size())) {
-        for (ArrayIndex i = 0; i < keys.size(); ++i) {
-            auto &key = keys[i];
-            auto &value = values[i];
-            if (key.isString() && value.isString()) {
-                auto userParameter = mProto.add_user_parameter();
-                userParameter->set_key(key.asString());
-                userParameter->set_value(value.asString());
-            }
-        }
-    }
-
-    loadStateFromProto();
-}
-
-void BootParameters::loadStateFromProto() {
-    // A missing key returns a safe, default value.
-    // Ignore invalid or missing parameters.
-    mIsSilentBoot = mProto.silent_boot();
-
-    for (const auto &param : mProto.user_parameter()) {
-        mParameters.push_back({.key = param.key().c_str(), .value = param.value().c_str()});
-    }
-}
-
-}  // namespace android
diff --git a/cmds/bootanimation/iot/BootParameters.h b/cmds/bootanimation/iot/BootParameters.h
deleted file mode 100644
index cbd1ca6..0000000
--- a/cmds/bootanimation/iot/BootParameters.h
+++ /dev/null
@@ -1,74 +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.
- */
-
-#ifndef _BOOTANIMATION_BOOT_PARAMETERS_H_
-#define _BOOTANIMATION_BOOT_PARAMETERS_H_
-
-#include <list>
-#include <string>
-#include <vector>
-
-#include <boot_action/boot_action.h>  // libandroidthings native API.
-#include <boot_parameters.pb.h>
-
-namespace android {
-
-// Provides access to the parameters set by DeviceManager.reboot().
-class BootParameters {
-public:
-    // Constructor loads the parameters for this boot and swaps the param files
-    // to clear the parameters for next boot.
-    BootParameters();
-
-    // Returns whether or not this is a silent boot.
-    bool isSilentBoot() const { return mIsSilentBoot; }
-
-    // Returns the additional boot parameters that were set on reboot.
-    const std::vector<ABootActionParameter>& getParameters() const { return mParameters; }
-
-    // Exposed for testing. Sets the parameters to the serialized proto.
-    void parseBootParameters(const std::string &contents);
-
-    // For devices that OTA from N to O.
-    // Exposed for testing. Sets the parameters to the raw JSON.
-    void parseLegacyBootParameters(const std::string &contents);
-
-    // Exposed for testing. Loads the contents from |nextBootFile| and replaces
-    // |lastBootFile| with |nextBootFile|.
-    static bool swapAndLoadBootConfigContents(const char *lastBootFile, const char *nextBootFile,
-                                              std::string *contents);
-
-  private:
-    void loadParameters();
-
-    // Replaces the legacy JSON blob with the updated version, allowing the
-    // framework to read it.
-    void storeParameters();
-
-    void loadStateFromProto();
-
-    bool mIsSilentBoot = false;
-
-    std::vector<ABootActionParameter> mParameters;
-
-    // Store the proto because mParameters makes a shallow copy.
-    android::things::proto::BootParameters mProto;
-};
-
-}  // namespace android
-
-
-#endif  // _BOOTANIMATION_BOOT_PARAMETERS_H_
diff --git a/cmds/bootanimation/iot/BootParameters_test.cpp b/cmds/bootanimation/iot/BootParameters_test.cpp
deleted file mode 100644
index d55bce6..0000000
--- a/cmds/bootanimation/iot/BootParameters_test.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BootParameters.h"
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android-base/file.h>
-#include <android-base/test_utils.h>
-#include <boot_parameters.pb.h>
-#include <gtest/gtest.h>
-
-namespace android {
-
-namespace {
-
-TEST(BootParametersTest, TestNoBootParametersIsNotSilent) {
-    android::things::proto::BootParameters proto;
-
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseBootParameters(proto.SerializeAsString());
-
-    ASSERT_FALSE(bootParameters.isSilentBoot());
-    ASSERT_EQ(0u, bootParameters.getParameters().size());
-}
-
-TEST(BootParametersTest, TestParseIsSilent) {
-    android::things::proto::BootParameters proto;
-    proto.set_silent_boot(true);
-
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseBootParameters(proto.SerializeAsString());
-
-    ASSERT_TRUE(bootParameters.isSilentBoot());
-}
-
-TEST(BootParametersTest, TestParseIsNotSilent) {
-    android::things::proto::BootParameters proto;
-    proto.set_silent_boot(false);
-
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseBootParameters(proto.SerializeAsString());
-
-    ASSERT_FALSE(bootParameters.isSilentBoot());
-}
-
-TEST(BootParametersTest, TestParseBootParameters) {
-    android::things::proto::BootParameters proto;
-    proto.set_silent_boot(false);
-
-    auto userParameter = proto.add_user_parameter();
-    userParameter->set_key("key1");
-    userParameter->set_value("value1");
-
-    userParameter = proto.add_user_parameter();
-    userParameter->set_key("key2");
-    userParameter->set_value("value2");
-
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseBootParameters(proto.SerializeAsString());
-
-    auto &parameters = bootParameters.getParameters();
-    ASSERT_EQ(2u, parameters.size());
-    ASSERT_STREQ(parameters[0].key, "key1");
-    ASSERT_STREQ(parameters[0].value, "value1");
-    ASSERT_STREQ(parameters[1].key, "key2");
-    ASSERT_STREQ(parameters[1].value, "value2");
-}
-
-TEST(BootParametersTest, TestParseLegacyDisableBootAnimationIsSilent) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":200,
-      "volume":100,
-      "boot_animation_disabled":1,
-      "param_names":[],
-      "param_values":[]
-    }
-    )");
-
-    ASSERT_TRUE(bootParameters.isSilentBoot());
-}
-
-TEST(BootParametersTest, TestParseLegacyZeroVolumeIsSilent) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":200,
-      "volume":0,
-      "boot_animation_disabled":0,
-      "param_names":[],
-      "param_values":[]
-    }
-    )");
-
-    ASSERT_TRUE(bootParameters.isSilentBoot());
-}
-
-TEST(BootParametersTest, TestParseLegacyDefaultVolumeIsSilent) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":200,
-      "volume":-1000,
-      "boot_animation_disabled":0,
-      "param_names":[],
-      "param_values":[]
-    }
-    )");
-
-    ASSERT_TRUE(bootParameters.isSilentBoot());
-}
-
-TEST(BootParametersTest, TestParseLegacyNotSilent) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":200,
-      "volume":500,
-      "boot_animation_disabled":0,
-      "param_names":[],
-      "param_values":[]
-    }
-    )");
-
-    ASSERT_FALSE(bootParameters.isSilentBoot());
-}
-
-TEST(BootParametersTest, TestParseLegacyParameters) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":200,
-      "volume":100,
-      "boot_animation_disabled":1,
-      "param_names":["key1", "key2"],
-      "param_values":["value1", "value2"]
-    }
-    )");
-
-    auto parameters = bootParameters.getParameters();
-    ASSERT_EQ(2u, parameters.size());
-    ASSERT_STREQ(parameters[0].key, "key1");
-    ASSERT_STREQ(parameters[0].value, "value1");
-    ASSERT_STREQ(parameters[1].key, "key2");
-    ASSERT_STREQ(parameters[1].value, "value2");
-}
-
-TEST(BootParametersTest, TestParseLegacyZeroParameters) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":200,
-      "volume":100,
-      "boot_animation_disabled":1,
-      "param_names":[],
-      "param_values":[]
-    }
-    )");
-
-    ASSERT_EQ(0u, bootParameters.getParameters().size());
-}
-
-TEST(BootParametersTest, TestMalformedLegacyParametersAreSkipped) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":500,
-      "volume":500,
-      "boot_animation_disabled":0,
-      "param_names":["key1", "key2"],
-      "param_values":[1, "value2"]
-    }
-    )");
-
-    auto parameters = bootParameters.getParameters();
-    ASSERT_EQ(1u, parameters.size());
-    ASSERT_STREQ(parameters[0].key, "key2");
-    ASSERT_STREQ(parameters[0].value, "value2");
-}
-
-TEST(BootParametersTest, TestLegacyUnequalParameterSizesAreSkipped) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":500,
-      "volume":500,
-      "boot_animation_disabled":0,
-      "param_names":["key1", "key2"],
-      "param_values":["value1"]
-    }
-    )");
-
-    ASSERT_EQ(0u, bootParameters.getParameters().size());
-}
-
-TEST(BootParametersTest, TestMissingLegacyBootParametersIsSilent) {
-    BootParameters bootParameters = BootParameters();
-    bootParameters.parseLegacyBootParameters(R"(
-    {
-      "brightness":500
-    }
-    )");
-
-    EXPECT_TRUE(bootParameters.isSilentBoot());
-    ASSERT_EQ(0u, bootParameters.getParameters().size());
-}
-
-TEST(BootParametersTest, TestLastFileIsRemovedOnError) {
-    TemporaryFile lastFile;
-    TemporaryDir tempDir;
-    std::string nonExistentFilePath(std::string(tempDir.path) + "/nonexistent");
-    std::string contents;
-
-    BootParameters::swapAndLoadBootConfigContents(lastFile.path, nonExistentFilePath.c_str(),
-                                                  &contents);
-
-    struct stat buf;
-    ASSERT_EQ(-1, lstat(lastFile.path, &buf));
-    ASSERT_TRUE(contents.empty());
-}
-
-TEST(BootParametersTest, TestNextFileIsRemovedLastFileExistsOnSuccess) {
-    TemporaryFile lastFile;
-    TemporaryFile nextFile;
-
-    base::WriteStringToFile("foo", nextFile.path);
-
-    std::string contents;
-    // Expected side effects:
-    // - |next_file| is moved to |last_file|
-    // - |contents| is the contents of |next_file| before being moved.
-    BootParameters::swapAndLoadBootConfigContents(lastFile.path, nextFile.path, &contents);
-
-    struct stat buf;
-    ASSERT_EQ(0, lstat(lastFile.path, &buf));
-    ASSERT_EQ(-1, lstat(nextFile.path, &buf));
-    ASSERT_EQ(contents, "foo");
-
-    contents.clear();
-    ASSERT_TRUE(base::ReadFileToString(lastFile.path, &contents));
-    ASSERT_EQ(contents, "foo");
-}
-
-}  // namespace
-
-}  // namespace android
diff --git a/cmds/bootanimation/iot/bootanim_iot.rc b/cmds/bootanimation/iot/bootanim_iot.rc
deleted file mode 100644
index 2fc1336..0000000
--- a/cmds/bootanimation/iot/bootanim_iot.rc
+++ /dev/null
@@ -1,2 +0,0 @@
-on post-fs-data
-    mkdir /data/misc/bootanimation 0777 root root
diff --git a/cmds/bootanimation/iot/iotbootanimation_main.cpp b/cmds/bootanimation/iot/iotbootanimation_main.cpp
deleted file mode 100644
index ae35297..0000000
--- a/cmds/bootanimation/iot/iotbootanimation_main.cpp
+++ /dev/null
@@ -1,132 +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.
- */
-
-#define LOG_TAG "IotBootAnimation"
-
-#include <base/files/file_util.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <cutils/properties.h>
-#include <sys/resource.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <BootAnimation.h>
-
-#include "BootAction.h"
-#include "BootAnimationUtil.h"
-#include "BootParameters.h"
-
-using namespace android;
-
-// Create a typedef for readability.
-typedef android::BootAnimation::Animation Animation;
-
-namespace {
-
-constexpr const char* kDefaultLibName = "libbootaction.so";
-
-class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {
-public:
-    BootActionAnimationCallbacks(std::unique_ptr<BootParameters> bootParameters)
-        : mBootParameters(std::move(bootParameters)) {}
-
-    void init(const Vector<Animation::Part>&) override {
-        std::string library_path("/oem/lib/");
-
-        // This value is optionally provided by the user and will be written to
-        // /oem/oem.prop.
-        char property[PROP_VALUE_MAX] = {0};
-        property_get("ro.oem.bootactions.lib", property, kDefaultLibName);
-        library_path += property;
-
-        if (!::base::PathExists(::base::FilePath(library_path))) {
-            ALOGI("Skipping boot actions: %s does not exist", library_path.c_str());
-            return;
-        }
-
-        mBootAction = new BootAction();
-        if (!mBootAction->init(library_path, mBootParameters)) {
-            mBootAction = nullptr;
-        }
-    };
-
-    void playPart(int partNumber, const Animation::Part&, int playNumber) override {
-        if (mBootAction != nullptr) {
-            mBootAction->startPart(partNumber, playNumber);
-        }
-    };
-
-    void shutdown() override {
-        if (mBootAction != nullptr) {
-            // If we have a bootaction we want to wait until we are actually
-            // told to shut down. If the animation exits early keep the action
-            // running.
-            char value[PROPERTY_VALUE_MAX] = {0};
-            for (int exitRequested = 0; exitRequested == 0; ) {
-                property_get("service.bootanim.exit", value, "0");
-                exitRequested = atoi(value);
-
-                // Poll value at 10hz.
-                if (exitRequested == 0) {
-                  usleep(100000);
-                }
-            }
-
-            mBootAction->shutdown();
-            // Give it two seconds to shut down.
-            sleep(2);
-            mBootAction = nullptr;
-        }
-    };
-
-private:
-    std::unique_ptr<BootParameters> mBootParameters;
-    sp<BootAction> mBootAction = nullptr;
-};
-
-}  // namespace
-
-int main() {
-    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
-
-    // Clear our params for next boot no matter what.
-    std::unique_ptr<BootParameters> bootParameters(new BootParameters());
-
-    if (bootAnimationDisabled()) {
-        ALOGI("boot animation disabled");
-        return 0;
-    }
-
-    waitForSurfaceFlinger();
-
-    sp<ProcessState> proc(ProcessState::self());
-    ProcessState::self()->startThreadPool();
-
-    bool isSilentBoot = bootParameters->isSilentBoot();
-    sp<BootActionAnimationCallbacks> callbacks =
-        new BootActionAnimationCallbacks(std::move(bootParameters));
-
-    // On silent boot, animations aren't displayed.
-    if (isSilentBoot) {
-        callbacks->init({});
-    } else {
-        sp<BootAnimation> boot = new BootAnimation(callbacks);
-    }
-
-    IPCThreadState::self()->joinThreadPool();
-    return 0;
-}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f6c72ea..35c4ceb 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -56,6 +56,7 @@
 import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/core/proto/android/view/enums.proto";
 import "frameworks/base/core/proto/android/wifi/enums.proto";
+import "frameworks/base/core/proto/android/stats/textclassifier/textclassifier_enums.proto";
 
 /**
  * The master atom class. This message defines all of the available
@@ -319,6 +320,16 @@
             217 [(log_from_module) = "permissioncontroller"];
         PermissionAppsFragmentViewed permission_apps_fragment_viewed =
             218  [(log_from_module) = "permissioncontroller"];
+        TextSelectionEvent text_selection_event =
+            219  [(log_from_module) = "textclassifier"];
+        TextLinkifyEvent text_linkify_event =
+            220  [(log_from_module) = "textclassifier"];
+        ConversationActionsEvent conversation_actions_event =
+            221  [(log_from_module) = "textclassifier"];
+        LanguageDetectionEvent language_detection_event =
+            222  [(log_from_module) = "textclassifier"];
+        ExclusionRectStateChanged exclusion_rect_state_changed = 223;
+        BackGesture back_gesture_reported_reported = 224;
     }
 
     // Pulled events will start at field 10000.
@@ -2500,6 +2511,41 @@
     optional State state = 1;
 }
 
+message BackGesture {
+    enum BackType {
+          DEFAULT_BACK_TYPE = 0;
+          COMPLETED = 1;
+          COMPLETED_REJECTED = 2; // successful because coming from rejected area
+          INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area
+          INCOMPLETE = 4;
+    }
+    optional BackType type = 1;
+
+    optional int32 y_coordinate = 2; // y coordinate for ACTION_DOWN event
+    enum WindowHorizontalLocation {
+        DEFAULT_LOCATION = 0;
+        LEFT = 1;
+        RIGHT = 2;
+    }
+    optional WindowHorizontalLocation x_location = 3;
+}
+
+message ExclusionRectStateChanged {
+    optional string component_name = 1;    // if not available, simply packageName
+    optional int32 requested_height = 2;   // px
+    optional int32 rejected_height = 3;    // px
+
+    enum WindowHorizontalLocation {
+        DEFAULT_LOCATION = 0;
+        LEFT = 1;
+        RIGHT = 2;
+    }
+    optional WindowHorizontalLocation x_location = 4;
+    optional bool landscape = 5;
+    optional bool splitscreen = 6;
+    optional int32 duration_millis = 7;
+}
+
 message LauncherUIChanged {
     optional android.stats.launcher.LauncherAction action = 1;
     optional android.stats.launcher.LauncherState src_state = 2;
@@ -6790,3 +6836,136 @@
     }
     optional Category category = 6;
 }
+
+/**
+ * Logs when there is a smart selection related event.
+ * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
+ * Logged from: TextClassifierEventLogger.java
+ */
+message TextSelectionEvent {
+    // A session ID.
+    optional string session_id = 1;
+
+    // Event type of this event.
+    optional android.stats.textclassifier.EventType event_type = 2;
+
+    // Name of the model that is involved in this event.
+    optional string model_name = 3;
+
+    // Type of widget that was involved in triggering this event.
+    optional android.stats.textclassifier.WidgetType widget_type = 4;
+
+    // Index of this event in a session.
+    optional int32 event_index = 5;
+
+    // Entity type that is involved.
+    optional string entity_type = 6;
+
+    // Relative word index of the start of the selection.
+    optional int32 relative_word_start_index = 7;
+
+    // Relative word (exclusive) index of the end of the selection.
+    optional int32 relative_word_end_index = 8;
+
+    // Relative word index of the start of the smart selection.
+    optional int32 relative_suggested_word_start_index = 9;
+
+    // Relative word (exclusive) index of the end of the smart selection.
+    optional int32 relative_suggested_word_end_index = 10;
+}
+
+/**
+ * Logs when there is a smart linkify related event.
+ * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
+ * Logged from: TextClassifierEventLogger.java
+ */
+message TextLinkifyEvent {
+    // A session ID.
+    optional string session_id = 1;
+
+    // Event type of this event.
+    optional android.stats.textclassifier.EventType event_type = 2;
+
+    // Name of the model that is involved in this event.
+    optional string model_name = 3;
+
+    // Type of widget that was involved in triggering this event.
+    optional android.stats.textclassifier.WidgetType widget_type = 4;
+
+    // Index of this event in a session.
+    optional int32 event_index = 5;
+
+    // Entity type that is involved.
+    optional string entity_type = 6;
+
+    // Number of links detected.
+    optional int32 num_links = 7;
+
+    // The total length of all links.
+    optional int32 linked_text_length = 8;
+
+    // Length of input text.
+    optional int32 text_length = 9;
+
+    // Time spent on generating links in ms.
+    optional int64 latency_millis = 10;
+}
+
+/**
+ * Logs when there is a conversation actions related event.
+ * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
+ * Logged from: TextClassifierEventLogger.java
+ */
+message ConversationActionsEvent {
+    // A session ID.
+    optional string session_id = 1;
+
+    // Event type of this event.
+    optional android.stats.textclassifier.EventType event_type = 2;
+
+    // Name of the model that is involved in this event.
+    optional string model_name = 3;
+
+    // Type of widget that was involved in triggering this event.
+    optional android.stats.textclassifier.WidgetType widget_type = 4;
+
+    // The first entity type that is involved.
+    optional string first_entity_type = 5;
+
+    // The second entity type that is involved.
+    optional string second_entity_type = 6;
+
+    // The third entity type that is involved.
+    optional string third_entity_type = 7;
+
+    // The score of the first entity type.
+    optional float score = 8;
+}
+
+/**
+ * Logs when there is a language detection related event.
+ * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
+ * Logged from: TextClassifierEventLogger.java
+ */
+message LanguageDetectionEvent {
+    // A session ID.
+    optional string session_id = 1;
+
+    // Event type of this event.
+    optional android.stats.textclassifier.EventType event_type = 2;
+
+    // Name of the model that is involved in this event.
+    optional string model_name = 3;
+
+    // Type of widget that was involved in triggering this event.
+    optional android.stats.textclassifier.WidgetType widget_type = 4;
+
+    // Detected language.
+    optional string language_tag = 5;
+
+    // Score of the detected language.
+    optional float score = 6;
+
+    // Position of this action.
+    optional int32 action_index = 7;
+}
diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-greylist-max-p.txt
index 25d45b0..351e71d 100644
--- a/config/hiddenapi-greylist-max-p.txt
+++ b/config/hiddenapi-greylist-max-p.txt
@@ -1,57 +1,14 @@
 Landroid/app/IInstrumentationWatcher$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IInstrumentationWatcher;
 Landroid/app/ISearchManager$Stub;-><init>()V
 Landroid/app/IUiModeManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IUiModeManager;
-Landroid/app/IUiModeManager;->disableCarMode(I)V
 Landroid/bluetooth/IBluetooth$Stub;-><init>()V
 Landroid/bluetooth/IBluetoothA2dp$Stub;-><init>()V
 Landroid/content/IIntentReceiver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentReceiver;
 Landroid/content/IIntentSender$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentSender;
-Landroid/net/IConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
-Landroid/net/IConnectivityManager;->reportInetCondition(II)V
-Landroid/os/BatteryStats$Counter;-><init>()V
-Landroid/os/BatteryStats$HistoryItem;->clear()V
-Landroid/os/BatteryStats$HistoryItem;->next:Landroid/os/BatteryStats$HistoryItem;
-Landroid/os/BatteryStats$HistoryItem;->same(Landroid/os/BatteryStats$HistoryItem;)Z
-Landroid/os/BatteryStats$HistoryItem;->setTo(JBLandroid/os/BatteryStats$HistoryItem;)V
-Landroid/os/BatteryStats$HistoryItem;->setTo(Landroid/os/BatteryStats$HistoryItem;)V
-Landroid/os/BatteryStats$Timer;-><init>()V
-Landroid/os/BatteryStats$Uid$Pkg;-><init>()V
-Landroid/os/BatteryStats$Uid$Proc;-><init>()V
-Landroid/os/BatteryStats$Uid$Sensor;-><init>()V
-Landroid/os/BatteryStats$Uid$Wakelock;-><init>()V
-Landroid/os/BatteryStats;-><init>()V
-Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J
-Landroid/os/BatteryStats;->getNetworkActivityBytes(II)J
-Landroid/os/CancellationSignal;->mCancelInProgress:Z
-Landroid/os/CancellationSignal;->mIsCanceled:Z
-Landroid/os/CancellationSignal;->mOnCancelListener:Landroid/os/CancellationSignal$OnCancelListener;
-Landroid/os/CancellationSignal;->mRemote:Landroid/os/ICancellationSignal;
-Landroid/os/CancellationSignal;->waitForCancelFinishedLocked()V
-Landroid/os/IPowerManager;->nap(J)V
-Landroid/os/Parcel;->mCreators:Ljava/util/HashMap;
-Landroid/os/PowerManager;->mHandler:Landroid/os/Handler;
-Landroid/os/Process;->sendSignalQuiet(II)V
-Landroid/os/Registrant;->getHandler()Landroid/os/Handler;
-Landroid/os/RegistrantList;->get(I)Ljava/lang/Object;
-Landroid/os/RemoteCallback;->mHandler:Landroid/os/Handler;
 Landroid/os/storage/IObbActionListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IObbActionListener;
-Landroid/os/SystemProperties;->native_add_change_callback()V
-Landroid/os/SystemProperties;->native_get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/SystemProperties;->native_get_boolean(Ljava/lang/String;Z)Z
-Landroid/os/SystemProperties;->native_get_int(Ljava/lang/String;I)I
-Landroid/os/SystemProperties;->native_set(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/os/UserHandle;->formatUid(Ljava/io/PrintWriter;I)V
-Landroid/os/WorkSource;->sGoneWork:Landroid/os/WorkSource;
-Landroid/os/WorkSource;->sNewbWork:Landroid/os/WorkSource;
-Landroid/os/WorkSource;->sTmpWorkSource:Landroid/os/WorkSource;
-Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z
 Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V
-Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V
-Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
 Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/view/IGraphicsStats$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IGraphicsStats;
-Landroid/view/IWindowManager;->setInTouchMode(Z)V
-Landroid/view/IWindowManager;->showStrictModeViolation(Z)V
 Lcom/android/internal/R$styleable;->AndroidManifestActivityAlias:[I
 Lcom/android/internal/R$styleable;->AndroidManifestGrantUriPermission:[I
 Lcom/android/internal/R$styleable;->AndroidManifestInstrumentation:[I
@@ -70,10 +27,3 @@
 Lcom/android/internal/R$styleable;->Searchable:[I
 Lcom/android/internal/R$styleable;->SearchableActionKey:[I
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub;-><init>()V
-Lcom/android/internal/telephony/ITelephony;->getDataActivity()I
-Lcom/android/internal/telephony/ITelephony;->getDataState()I
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCallForwardingChanged(Z)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCellLocation(Landroid/os/Bundle;)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataActivity(I)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyOtaspChanged(II)V
-Lcom/android/internal/view/BaseIWindow;-><init>()V
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index c30a6f4..eb53b7c 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -121,8 +121,6 @@
 Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap;
 Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V
 Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
-Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V
-Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V
 Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
 Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -194,7 +192,6 @@
 Landroid/content/UndoManager;-><init>()V
 Landroid/database/IContentObserver$Stub;-><init>()V
 Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/database/IContentObserver;
-Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V
 Landroid/database/sqlite/SQLiteConnectionPool;->$assertionsDisabled:Z
 Landroid/database/sqlite/SQLiteDatabase;->$assertionsDisabled:Z
 Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager;
@@ -723,9 +720,6 @@
 Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z
 Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
 Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider;
-Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)V
-Lcom/android/internal/location/ILocationProvider;->setLocationProviderManager(Lcom/android/internal/location/ILocationProviderManager;)V
-Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V
 Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V
 Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager;
 Lcom/android/internal/logging/MetricsLogger;-><init>()V
@@ -736,7 +730,6 @@
 Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService;
 Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService;
 Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback;
-Lcom/android/internal/preference/YesNoPreference;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
 Lcom/android/internal/R$anim;->fade_in:I
 Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I
 Lcom/android/internal/R$array;->config_autoBrightnessLevels:I
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 03e3b82..ea50999 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -563,6 +563,7 @@
 android.app.job.JobParameters$1
 android.app.job.JobParameters
 android.app.job.JobScheduler
+android.app.job.JobSchedulerFrameworkInitializer
 android.app.job.JobService$1
 android.app.job.JobService
 android.app.job.JobServiceEngine$JobHandler
diff --git a/config/preloaded-classes-extra b/config/preloaded-classes-extra
index 09f393a..94849fb 100644
--- a/config/preloaded-classes-extra
+++ b/config/preloaded-classes-extra
@@ -1,3 +1,6 @@
+# JobSchedulerFrameworkInitializer must always be preloaded because it registers the job scheduler
+# service wrapper to SystemServiceRegistry.
+android.app.job.JobSchedulerFrameworkInitializer
 android.icu.impl.coll.CollationRoot
 android.icu.impl.IDNA2003
 android.icu.impl.number.Parse
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 926044b..b8d9575 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -177,6 +177,13 @@
     private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId";
 
     /**
+     * The id of the display where the caller was on.
+     * @see #setCallerDisplayId(int)
+     * @hide
+     */
+    private static final String KEY_CALLER_DISPLAY_ID = "android.activity.callerDisplayId";
+
+    /**
      * The windowing mode the activity should be launched into.
      * @hide
      */
@@ -269,6 +276,8 @@
             = "android:activity.remoteAnimationAdapter";
 
     /** @hide */
+    public static final int ANIM_UNDEFINED = -1;
+    /** @hide */
     public static final int ANIM_NONE = 0;
     /** @hide */
     public static final int ANIM_CUSTOM = 1;
@@ -299,7 +308,7 @@
 
     private String mPackageName;
     private Rect mLaunchBounds;
-    private int mAnimationType = ANIM_NONE;
+    private int mAnimationType = ANIM_UNDEFINED;
     private int mCustomEnterResId;
     private int mCustomExitResId;
     private int mCustomInPlaceResId;
@@ -318,6 +327,7 @@
     private int mExitCoordinatorIndex;
     private PendingIntent mUsageTimeReport;
     private int mLaunchDisplayId = INVALID_DISPLAY;
+    private int mCallerDisplayId = INVALID_DISPLAY;
     @WindowConfiguration.WindowingMode
     private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
     @WindowConfiguration.ActivityType
@@ -896,7 +906,7 @@
             Slog.w(TAG, e);
         }
         mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS);
-        mAnimationType = opts.getInt(KEY_ANIM_TYPE);
+        mAnimationType = opts.getInt(KEY_ANIM_TYPE, ANIM_UNDEFINED);
         switch (mAnimationType) {
             case ANIM_CUSTOM:
                 mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
@@ -945,6 +955,7 @@
         }
         mLockTaskMode = opts.getBoolean(KEY_LOCK_TASK_MODE, false);
         mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
+        mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
         mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
         mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
         mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
@@ -1204,6 +1215,17 @@
     }
 
     /** @hide */
+    public int getCallerDisplayId() {
+        return mCallerDisplayId;
+    }
+
+    /** @hide */
+    public ActivityOptions setCallerDisplayId(int callerDisplayId) {
+        mCallerDisplayId = callerDisplayId;
+        return this;
+    }
+
+    /** @hide */
     public int getLaunchWindowingMode() {
         return mLaunchWindowingMode;
     }
@@ -1447,7 +1469,9 @@
         if (mLaunchBounds != null) {
             b.putParcelable(KEY_LAUNCH_BOUNDS, mLaunchBounds);
         }
-        b.putInt(KEY_ANIM_TYPE, mAnimationType);
+        if (mAnimationType != ANIM_UNDEFINED) {
+            b.putInt(KEY_ANIM_TYPE, mAnimationType);
+        }
         if (mUsageTimeReport != null) {
             b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport);
         }
@@ -1506,6 +1530,9 @@
         if (mLaunchDisplayId != INVALID_DISPLAY) {
             b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
         }
+        if (mCallerDisplayId != INVALID_DISPLAY) {
+            b.putInt(KEY_CALLER_DISPLAY_ID, mCallerDisplayId);
+        }
         if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
             b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
         }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2b4d4f8b..50f945b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -80,6 +80,7 @@
 import android.graphics.HardwareRenderer;
 import android.graphics.ImageDecoder;
 import android.hardware.display.DisplayManagerGlobal;
+import android.inputmethodservice.InputMethodService;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.Proxy;
@@ -455,6 +456,8 @@
 
     Bundle mCoreSettings = null;
 
+    boolean mHasImeComponent = false;
+
     /** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
     public static final class ActivityClientRecord {
         @UnsupportedAppUsage
@@ -5360,7 +5363,11 @@
             }
             final int NSVC = mServices.size();
             for (int i=0; i<NSVC; i++) {
-                callbacks.add(mServices.valueAt(i));
+                final ComponentCallbacks2 serviceComp = mServices.valueAt(i);
+                if (serviceComp instanceof InputMethodService) {
+                    mHasImeComponent = true;
+                }
+                callbacks.add(serviceComp);
             }
         }
         synchronized (mProviderMap) {
@@ -5600,6 +5607,10 @@
             }
 
             if (config == null) {
+                // TODO (b/135719017): Temporary log for debugging IME service.
+                if (Build.IS_DEBUGGABLE && mHasImeComponent) {
+                    Log.w(TAG, "handleConfigurationChanged for IME app but config is null");
+                }
                 return;
             }
 
@@ -5621,6 +5632,12 @@
                 mConfiguration = new Configuration();
             }
             if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {
+                // TODO (b/135719017): Temporary log for debugging IME service.
+                if (Build.IS_DEBUGGABLE && mHasImeComponent) {
+                    Log.w(TAG, "handleConfigurationChanged for IME app but config seq is obsolete "
+                            + ", config=" + config
+                            + ", mConfiguration=" + mConfiguration);
+                }
                 return;
             }
 
@@ -5652,6 +5669,13 @@
                             config);
                 } else if (!equivalent) {
                     performConfigurationChanged(cb, config);
+                } else {
+                    // TODO (b/135719017): Temporary log for debugging IME service.
+                    if (Build.IS_DEBUGGABLE && cb instanceof InputMethodService) {
+                        Log.w(TAG, "performConfigurationChanged didn't callback to IME "
+                                + ", configDiff=" + configDiff
+                                + ", mConfiguration=" + mConfiguration);
+                    }
                 }
             }
         }
@@ -7142,6 +7166,12 @@
         ViewRootImpl.ConfigChangedCallback configChangedCallback
                 = (Configuration globalConfig) -> {
             synchronized (mResourcesManager) {
+                // TODO (b/135719017): Temporary log for debugging IME service.
+                if (Build.IS_DEBUGGABLE && mHasImeComponent) {
+                    Log.d(TAG, "ViewRootImpl.ConfigChangedCallback for IME, "
+                            + "config=" + globalConfig);
+                }
+
                 // We need to apply this change to the resources immediately, because upon returning
                 // the view hierarchy will be informed about it.
                 if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index fb72e65..d20cc41 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -834,9 +834,12 @@
     public static final int OP_ACCESS_ACCESSIBILITY = 88;
     /** @hide Read the device identifiers (IMEI / MEID, IMSI, SIM / Build serial) */
     public static final int OP_READ_DEVICE_IDENTIFIERS = 89;
+    /** @hide Query all apps on device, regardless of declarations in the calling app manifest */
+    public static final int OP_QUERY_ALL_PACKAGES = 90;
+
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 90;
+    public static final int _NUM_OP = 91;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1112,6 +1115,8 @@
     public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
     /** @hide Read device identifiers */
     public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
+    /** @hide Query all packages on device */
+    public static final String OPSTR_QUERY_ALL_PACKAGES = "android:query_all_packages";
 
     // Warning: If an permission is added here it also has to be added to
     // com.android.packageinstaller.permission.utils.EventLogger
@@ -1273,6 +1278,7 @@
             OP_LEGACY_STORAGE,                  // LEGACY_STORAGE
             OP_ACCESS_ACCESSIBILITY,            // ACCESS_ACCESSIBILITY
             OP_READ_DEVICE_IDENTIFIERS,         // READ_DEVICE_IDENTIFIERS
+            OP_QUERY_ALL_PACKAGES,              // QUERY_ALL_PACKAGES
     };
 
     /**
@@ -1369,6 +1375,7 @@
             OPSTR_LEGACY_STORAGE,
             OPSTR_ACCESS_ACCESSIBILITY,
             OPSTR_READ_DEVICE_IDENTIFIERS,
+            OPSTR_QUERY_ALL_PACKAGES,
     };
 
     /**
@@ -1466,6 +1473,7 @@
             "LEGACY_STORAGE",
             "ACCESS_ACCESSIBILITY",
             "READ_DEVICE_IDENTIFIERS",
+            "QUERY_ALL_PACKAGES",
     };
 
     /**
@@ -1564,6 +1572,7 @@
             null, // no permission for OP_LEGACY_STORAGE
             null, // no permission for OP_ACCESS_ACCESSIBILITY
             null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS
+            null, // no permission for OP_QUERY_ALL_PACKAGES
     };
 
     /**
@@ -1662,6 +1671,7 @@
             null, // LEGACY_STORAGE
             null, // ACCESS_ACCESSIBILITY
             null, // READ_DEVICE_IDENTIFIERS
+            null, // QUERY_ALL_PACKAGES
     };
 
     /**
@@ -1759,6 +1769,7 @@
             false, // LEGACY_STORAGE
             false, // ACCESS_ACCESSIBILITY
             false, // READ_DEVICE_IDENTIFIERS
+            false, // QUERY_ALL_PACKAGES
     };
 
     /**
@@ -1855,6 +1866,7 @@
             AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE
             AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY
             AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS
+            AppOpsManager.MODE_DEFAULT, // QUERY_ALL_PACKAGES
     };
 
     /**
@@ -1955,6 +1967,7 @@
             false, // LEGACY_STORAGE
             false, // ACCESS_ACCESSIBILITY
             false, // READ_DEVICE_IDENTIFIERS
+            false, // QUERY_ALL_PACKAGES
     };
 
     /**
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 1166cb5..80c9ba2 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -132,6 +132,9 @@
      */
     public final static String COLUMN_STATUS = Downloads.Impl.COLUMN_STATUS;
 
+    /** {@hide} */
+    public final static String COLUMN_FILE_NAME_HINT = Downloads.Impl.COLUMN_FILE_NAME_HINT;
+
     /**
      * Provides more detail on the status of the download.  Its meaning depends on the value of
      * {@link #COLUMN_STATUS}.
@@ -169,6 +172,9 @@
      */
     public static final String COLUMN_MEDIAPROVIDER_URI = Downloads.Impl.COLUMN_MEDIAPROVIDER_URI;
 
+    /** {@hide} */
+    public static final String COLUMN_DESTINATION = Downloads.Impl.COLUMN_DESTINATION;
+
     /** @hide */
     @TestApi
     public static final String COLUMN_MEDIASTORE_URI = Downloads.Impl.COLUMN_MEDIASTORE_URI;
@@ -340,26 +346,22 @@
      */
     @UnsupportedAppUsage
     public static final String[] UNDERLYING_COLUMNS = new String[] {
-        Downloads.Impl._ID,
-        Downloads.Impl._DATA + " AS " + COLUMN_LOCAL_FILENAME,
-        Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
-        Downloads.Impl.COLUMN_DESTINATION,
-        Downloads.Impl.COLUMN_TITLE,
-        Downloads.Impl.COLUMN_DESCRIPTION,
-        Downloads.Impl.COLUMN_URI,
-        Downloads.Impl.COLUMN_STATUS,
-        Downloads.Impl.COLUMN_FILE_NAME_HINT,
-        Downloads.Impl.COLUMN_MIME_TYPE + " AS " + COLUMN_MEDIA_TYPE,
-        Downloads.Impl.COLUMN_TOTAL_BYTES + " AS " + COLUMN_TOTAL_SIZE_BYTES,
-        Downloads.Impl.COLUMN_LAST_MODIFICATION + " AS " + COLUMN_LAST_MODIFIED_TIMESTAMP,
-        Downloads.Impl.COLUMN_CURRENT_BYTES + " AS " + COLUMN_BYTES_DOWNLOADED_SO_FAR,
-        Downloads.Impl.COLUMN_ALLOW_WRITE,
-        /* add the following 'computed' columns to the cursor.
-         * they are not 'returned' by the database, but their inclusion
-         * eliminates need to have lot of methods in CursorTranslator
-         */
-        "'placeholder' AS " + COLUMN_LOCAL_URI,
-        "'placeholder' AS " + COLUMN_REASON
+        DownloadManager.COLUMN_ID,
+        DownloadManager.COLUMN_LOCAL_FILENAME,
+        DownloadManager.COLUMN_MEDIAPROVIDER_URI,
+        DownloadManager.COLUMN_DESTINATION,
+        DownloadManager.COLUMN_TITLE,
+        DownloadManager.COLUMN_DESCRIPTION,
+        DownloadManager.COLUMN_URI,
+        DownloadManager.COLUMN_STATUS,
+        DownloadManager.COLUMN_FILE_NAME_HINT,
+        DownloadManager.COLUMN_MEDIA_TYPE,
+        DownloadManager.COLUMN_TOTAL_SIZE_BYTES,
+        DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP,
+        DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR,
+        DownloadManager.COLUMN_ALLOW_WRITE,
+        DownloadManager.COLUMN_LOCAL_URI,
+        DownloadManager.COLUMN_REASON
     };
 
     /**
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index cae54b6..f2c9f61 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -30,6 +30,7 @@
     /**
      * Disables the car mode.
      */
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void disableCarMode(int flags);
 
     /**
diff --git a/core/java/android/app/JobSchedulerImpl.java b/core/java/android/app/JobSchedulerImpl.java
index e877018..924a708 100644
--- a/core/java/android/app/JobSchedulerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -26,6 +26,9 @@
 
 import java.util.List;
 
+
+// APEX NOTE: Class path referred to by robolectric, so can't move it.
+
 /**
  * Concrete implementation of the JobScheduler interface
  * @hide 
@@ -33,7 +36,7 @@
 public class JobSchedulerImpl extends JobScheduler {
     IJobScheduler mBinder;
 
-    /* package */ JobSchedulerImpl(IJobScheduler binder) {
+    public JobSchedulerImpl(IJobScheduler binder) {
         mBinder = binder;
     }
 
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 6f7a060..4b4a071 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -893,6 +893,17 @@
             String resolvedType = intent != null ?
                     intent.resolveTypeIfNeeded(context.getContentResolver())
                     : null;
+
+            if (context != null && isActivity()) {
+                // Set the context display id as preferred for this activity launches, so that it
+                // can land on caller's display. Or just brought the task to front at the display
+                // where it was on since it has higher preference.
+                ActivityOptions activityOptions = options != null ? new ActivityOptions(options)
+                        : ActivityOptions.makeBasic();
+                activityOptions.setCallerDisplayId(context.getDisplayId());
+                options = activityOptions.toBundle();
+            }
+
             return ActivityManager.getService().sendIntentSender(
                     mTarget, mWhitelistToken, code, intent, resolvedType,
                     onFinished != null
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index cfe2cf0..5034b53 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -23,8 +23,6 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.contentsuggestions.ContentSuggestionsManager;
 import android.app.contentsuggestions.IContentSuggestionsManager;
-import android.app.job.IJobScheduler;
-import android.app.job.JobScheduler;
 import android.app.prediction.AppPredictionManager;
 import android.app.role.RoleControllerManager;
 import android.app.role.RoleManager;
@@ -198,12 +196,15 @@
 import com.android.internal.policy.PhoneLayoutInflater;
 
 import java.util.Map;
+import java.util.function.Function;
 
 /**
  * Manages all of the system services that can be returned by {@link Context#getSystemService}.
  * Used by {@link ContextImpl}.
+ *
+ * @hide
  */
-final class SystemServiceRegistry {
+public final class SystemServiceRegistry {
     private static final String TAG = "SystemServiceRegistry";
 
     // Service registry information.
@@ -979,14 +980,6 @@
                 return new NetworkStatsManager(ctx.getOuterContext());
             }});
 
-        registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
-                new StaticServiceFetcher<JobScheduler>() {
-            @Override
-            public JobScheduler createService() throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getServiceOrThrow(Context.JOB_SCHEDULER_SERVICE);
-                return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
-            }});
-
         registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,
                 new StaticServiceFetcher<PersistentDataBlockManager>() {
             @Override
@@ -1324,6 +1317,22 @@
     }
 
     /**
+     * APEX modules will use it to register their service wrapper.
+     *
+     * @hide
+     */
+    public static <T> void registerStaticService(String serviceName, Class<T> serviceClass,
+            Function<IBinder, T> serviceFetcher) {
+        registerService(serviceName, serviceClass,
+                new StaticServiceFetcher<T>() {
+                    @Override
+                    public T createService() throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(serviceName);
+                        return serviceFetcher.apply(b);
+                    }});
+    }
+
+    /**
      * Base interface for classes that fetch services.
      * These objects must only be created during static initialization.
      */
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 325a54b..d305238 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -930,6 +930,9 @@
      * {@link android.service.wallpaper.WallpaperService.Engine#onComputeColors()
      *     WallpaperService.Engine#onComputeColors()}.</li>
      * </ul>
+     * <p>Please note that this API will go through IPC and may take some time to
+     * calculate the wallpaper color, which could block the caller thread, so it is
+     * not recommended to call this in the UI thread.</p>
      *
      * @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or
      *     {@link #FLAG_LOCK}.
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 3fca311..86e768d 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -641,6 +641,7 @@
         int mMaxEms = -1;
         int mMaxLength = -1;
         @Nullable String mTextIdEntry;
+        @Nullable String mHintIdEntry;
         @AutofillImportance int mImportantForAutofill;
 
         // POJO used to override some autofill-related values when the node is parcelized.
@@ -688,18 +689,19 @@
         static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
         static final int FLAGS_ALL_CONTROL = 0xfff00000;
 
-        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID =         0x001;
-        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID = 0x002;
-        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE =           0x004;
-        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE =            0x008;
-        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS =           0x010;
-        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS =         0x020;
-        static final int AUTOFILL_FLAGS_HAS_HTML_INFO =                0x040;
-        static final int AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY =            0x080;
-        static final int AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS =             0x100;
-        static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS =             0x200;
-        static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH =          0x400;
-        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_SESSION_ID =      0x800;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID =         0x0001;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID = 0x0002;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE =           0x0004;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE =            0x0008;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS =           0x0010;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS =         0x0020;
+        static final int AUTOFILL_FLAGS_HAS_HTML_INFO =                0x0040;
+        static final int AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY =            0x0080;
+        static final int AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS =             0x0100;
+        static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS =             0x0200;
+        static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH =          0x0400;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_SESSION_ID =      0x0800;
+        static final int AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY =            0x1000;
 
         int mFlags;
         int mAutofillFlags;
@@ -786,6 +788,9 @@
                 if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
                     mTextIdEntry = preader.readString();
                 }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY) != 0) {
+                    mHintIdEntry = preader.readString();
+                }
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 mX = in.readInt();
@@ -934,6 +939,9 @@
             if (mTextIdEntry != null) {
                 autofillFlags |= AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY;
             }
+            if (mHintIdEntry != null) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY;
+            }
 
             pwriter.writeString(mClassName);
 
@@ -1011,6 +1019,9 @@
                 if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
                     pwriter.writeString(mTextIdEntry);
                 }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY) != 0) {
+                    pwriter.writeString(mHintIdEntry);
+                }
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 out.writeInt(mX);
@@ -1586,6 +1597,17 @@
         }
 
         /**
+         * Gets the identifier used to set the hint associated with this view.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
+         * not for assist purposes.
+         */
+        @Nullable
+        public String getHintIdEntry() {
+            return mHintIdEntry;
+        }
+
+        /**
          * Return a Bundle containing optional vendor-specific extension information.
          */
         public Bundle getExtras() {
@@ -1853,6 +1875,11 @@
         }
 
         @Override
+        public void setHintIdEntry(@NonNull String entryName) {
+            mNode.mHintIdEntry = Preconditions.checkNotNull(entryName);
+        }
+
+        @Override
         public CharSequence getText() {
             return mNode.mText != null ? mNode.mText.mText : null;
         }
@@ -2266,6 +2293,7 @@
         String hint = node.getHint();
         if (hint != null) {
             Log.i(TAG, prefix + "  Hint: " + hint);
+            Log.i(TAG, prefix + "  Resource id: " + node.getHintIdEntry());
         }
         Bundle extras = node.getExtras();
         if (extras != null) {
diff --git a/core/java/android/app/job/JobSchedulerFrameworkInitializer.java b/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
new file mode 100644
index 0000000..cf2979c
--- /dev/null
+++ b/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.job;
+
+import android.app.JobSchedulerImpl;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+
+/**
+ * This class needs to be pre-loaded by zygote.  This is where the job scheduler service wrapper
+ * is registered.
+ *
+ * @hide
+ */
+public class JobSchedulerFrameworkInitializer {
+    static {
+        SystemServiceRegistry.registerStaticService(
+                Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
+                (b) -> new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)));
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 591c418..36f3a1e 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -441,6 +441,43 @@
     }
 
     /**
+     * Checks whether a value set presented by a bitmask has zero or single bit
+     *
+     * @param valueSet the value set presented by a bitmask
+     * @return true if the valueSet contains zero or single bit, otherwise false.
+     */
+    private static boolean hasSingleBit(int valueSet) {
+        return (valueSet == 0 || (valueSet & (valueSet - 1)) == 0);
+    }
+
+    /**
+     * Checks whether the object contains none or single sample rate.
+     *
+     * @return true if the object contains none or single sample rate, otherwise false.
+     */
+    public boolean hasSingleSampleRate() {
+        return hasSingleBit(mSampleRate);
+    }
+
+    /**
+     * Checks whether the object contains none or single bits per sample.
+     *
+     * @return true if the object contains none or single bits per sample, otherwise false.
+     */
+    public boolean hasSingleBitsPerSample() {
+        return hasSingleBit(mBitsPerSample);
+    }
+
+    /**
+     * Checks whether the object contains none or single channel mode.
+     *
+     * @return true if the object contains none or single channel mode, otherwise false.
+     */
+    public boolean hasSingleChannelMode() {
+        return hasSingleBit(mChannelMode);
+    }
+
+    /**
      * Checks whether the audio feeding parameters are same.
      *
      * @param other the codec config to compare against
@@ -451,4 +488,58 @@
                 && other.mBitsPerSample == mBitsPerSample
                 && other.mChannelMode == mChannelMode);
     }
+
+    /**
+     * Checks whether another codec config has the similar feeding parameters.
+     * Any parameters with NONE value will be considered to be a wildcard matching.
+     *
+     * @param other the codec config to compare against
+     * @return true if the audio feeding parameters are similar, otherwise false.
+     */
+    public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) {
+        if (other == null || mCodecType != other.mCodecType) {
+            return false;
+        }
+        int sampleRate = other.mSampleRate;
+        if (mSampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE
+                || sampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE) {
+            sampleRate = mSampleRate;
+        }
+        int bitsPerSample = other.mBitsPerSample;
+        if (mBitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE
+                || bitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
+            bitsPerSample = mBitsPerSample;
+        }
+        int channelMode = other.mChannelMode;
+        if (mChannelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE
+                || channelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE) {
+            channelMode = mChannelMode;
+        }
+        return sameAudioFeedingParameters(new BluetoothCodecConfig(
+                mCodecType, /* priority */ 0, sampleRate, bitsPerSample, channelMode,
+                /* specific1 */ 0, /* specific2 */ 0, /* specific3 */ 0,
+                /* specific4 */ 0));
+    }
+
+    /**
+     * Checks whether the codec specific parameters are the same.
+     *
+     * @param other the codec config to compare against
+     * @return true if the codec specific parameters are the same, otherwise false.
+     */
+    public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) {
+        if (other == null && mCodecType != other.mCodecType) {
+            return false;
+        }
+        // Currently we only care about the LDAC Playback Quality at CodecSpecific1
+        switch (mCodecType) {
+            case SOURCE_CODEC_TYPE_LDAC:
+                if (mCodecSpecific1 != other.mCodecSpecific1) {
+                    return false;
+                }
+                // fall through
+            default:
+                return true;
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
index 58b6aea..58a764a 100644
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -89,6 +89,43 @@
         return Arrays.asList(c1).containsAll(Arrays.asList(c2));
     }
 
+    /**
+     * Checks whether the codec config matches the selectable capabilities.
+     * Any parameters of the codec config with NONE value will be considered a wildcard matching.
+     *
+     * @param codecConfig the codec config to compare against
+     * @return true if the codec config matches, otherwise false
+     */
+    public boolean isCodecConfigSelectable(BluetoothCodecConfig codecConfig) {
+        if (codecConfig == null || !codecConfig.hasSingleSampleRate()
+                || !codecConfig.hasSingleBitsPerSample() || !codecConfig.hasSingleChannelMode()) {
+            return false;
+        }
+        for (BluetoothCodecConfig selectableConfig : mCodecsSelectableCapabilities) {
+            if (codecConfig.getCodecType() != selectableConfig.getCodecType()) {
+                continue;
+            }
+            int sampleRate = codecConfig.getSampleRate();
+            if ((sampleRate & selectableConfig.getSampleRate()) == 0
+                    && sampleRate != BluetoothCodecConfig.SAMPLE_RATE_NONE) {
+                continue;
+            }
+            int bitsPerSample = codecConfig.getBitsPerSample();
+            if ((bitsPerSample & selectableConfig.getBitsPerSample()) == 0
+                    && bitsPerSample != BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
+                continue;
+            }
+            int channelMode = codecConfig.getChannelMode();
+            if ((channelMode & selectableConfig.getChannelMode()) == 0
+                    && channelMode != BluetoothCodecConfig.CHANNEL_MODE_NONE) {
+                continue;
+            }
+            return true;
+        }
+        return false;
+    }
+
+
     @Override
     public int hashCode() {
         return Objects.hash(mCodecConfig, mCodecsLocalCapabilities,
diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
index 5f73e55..c9dc019 100644
--- a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
+++ b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
@@ -18,6 +18,8 @@
 
 /** @hide */
 interface ICompanionDeviceDiscoveryServiceCallback {
+    @UnsupportedAppUsage
     oneway void onDeviceSelected(String packageName, int userId, String deviceAddress);
+    @UnsupportedAppUsage
     oneway void onDeviceSelectionCancel();
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7a013f1..73bc908 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3197,6 +3197,7 @@
             TELEPHONY_SERVICE,
             TELEPHONY_SUBSCRIPTION_SERVICE,
             CARRIER_CONFIG_SERVICE,
+            EUICC_SERVICE,
             TELECOM_SERVICE,
             CLIPBOARD_SERVICE,
             INPUT_METHOD_SERVICE,
@@ -3387,6 +3388,8 @@
      * @see android.telephony.SubscriptionManager
      * @see #CARRIER_CONFIG_SERVICE
      * @see android.telephony.CarrierConfigManager
+     * @see #EUICC_SERVICE
+     * @see android.telephony.euicc.EuiccManager
      * @see #INPUT_METHOD_SERVICE
      * @see android.view.inputmethod.InputMethodManager
      * @see #UI_MODE_SERVICE
diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl
index 22dc9fe..6235566 100644
--- a/core/java/android/database/IContentObserver.aidl
+++ b/core/java/android/database/IContentObserver.aidl
@@ -29,5 +29,6 @@
      * observed. selfUpdate is true if the update was caused by a call to
      * commit on the cursor that is being observed.
      */
+    @UnsupportedAppUsage
     oneway void onChange(boolean selfUpdate, in Uri uri, int userId);
 }
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index cc8c182..68857da9 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -2337,6 +2337,12 @@
             final CaptureCallbackHolder holder =
                     CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
 
+            if (holder == null) {
+                Log.e(TAG, String.format("Receive capture error on unknown request ID %d",
+                        requestId));
+                return;
+            }
+
             final CaptureRequest request = holder.getRequest(subsequenceId);
 
             Runnable failureDispatch = null;
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index c135c8a..76304bd 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -26,6 +26,9 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -257,9 +260,22 @@
 
     private final Bundle mBundle;
 
+    // Lazily computed hash code based upon the contents of mBundle.
+    private Integer mHashCode;
+
     @Override
     public int hashCode() {
-        return mBundle.hashCode();
+        if (mHashCode == null) {
+            List<String> keys = new ArrayList<String>(mBundle.keySet());
+            keys.sort(null);
+            Object[] objs = new Object[2 * keys.size()];
+            for (int i = 0; i < keys.size(); i++) {
+                objs[2 * i] = keys.get(i);
+                objs[2 * i + 1] = mBundle.get(keys.get(i));
+            }
+            mHashCode = Arrays.hashCode(objs);
+        }
+        return mHashCode;
     }
 
     @Override
@@ -626,6 +642,8 @@
         String key = getKeyFromNativeKey(nativeKey);
         try {
             putInt(mBundle, key, value);
+            // Invalidate mHashCode to force it to be recomputed.
+            mHashCode = null;
             return 0;
         } catch (IllegalArgumentException ex) {
             return -1;
@@ -639,6 +657,8 @@
             return -1;
         }
         mBundle.putString(key, value);
+        // Invalidate mHashCode to force it to be recomputed.
+        mHashCode = null;
         return 0;
     }
 
@@ -653,6 +673,8 @@
             bmp = BitmapFactory.decodeByteArray(value, 0, value.length);
             if (bmp != null) {
                 mBundle.putParcelable(key, bmp);
+                // Invalidate mHashCode to force it to be recomputed.
+                mHashCode = null;
                 return 0;
             }
         } catch (Exception e) {
@@ -668,6 +690,8 @@
         }
         mBundle.putParcelable(key, new RadioMetadata.Clock(
             utcEpochSeconds, timezoneOffsetInMinutes));
+        // Invalidate mHashCode to force it to be recomputed.
+        mHashCode = null;
         return 0;
     }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 61648dc..5f662f9 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -52,6 +52,7 @@
     @UnsupportedAppUsage
     NetworkInfo getActiveNetworkInfo();
     NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked);
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     NetworkInfo getNetworkInfo(int networkType);
     NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked);
     @UnsupportedAppUsage
@@ -112,6 +113,7 @@
 
     int setUsbTethering(boolean enable, String callerPkg);
 
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void reportInetCondition(int networkType, int percentage);
 
     void reportNetworkConnectivity(in Network network, boolean hasConnectivity);
diff --git a/core/java/android/net/LinkQualityInfo.java b/core/java/android/net/LinkQualityInfo.java
index 3c5d474..2e6915f 100644
--- a/core/java/android/net/LinkQualityInfo.java
+++ b/core/java/android/net/LinkQualityInfo.java
@@ -24,8 +24,8 @@
  *  Class that represents useful attributes of generic network links
  *  such as the upload/download throughput or packet error rate.
  *  Generally speaking, you should be dealing with instances of
- *  LinkQualityInfo subclasses, such as {@link android.net.#WifiLinkQualityInfo}
- *  or {@link android.net.#MobileLinkQualityInfo} which provide additional
+ *  LinkQualityInfo subclasses, such as {@link android.net.WifiLinkQualityInfo}
+ *  or {@link android.net.MobileLinkQualityInfo} which provide additional
  *  information.
  *  @hide
  */
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index caa6a43..a399e83 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -64,6 +64,10 @@
  * @hide
  */
 public abstract class BatteryStats implements Parcelable {
+
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public BatteryStats() {}
+
     private static final String TAG = "BatteryStats";
 
     private static final boolean LOCAL_LOGV = false;
@@ -407,6 +411,9 @@
      */
     public static abstract class Counter {
 
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+        public Counter() {}
+
         /**
          * Returns the count associated with this Counter for the
          * selected type of statistics.
@@ -516,6 +523,9 @@
      */
     public static abstract class Timer {
 
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+        public Timer() {}
+
         /**
          * Returns the count associated with this Timer for the
          * selected type of statistics.
@@ -671,6 +681,9 @@
          * The statistics associated with a particular wake lock.
          */
         public static abstract class Wakelock {
+            @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+            public Wakelock() {}
+
             @UnsupportedAppUsage
             public abstract Timer getWakeTime(int type);
         }
@@ -948,6 +961,10 @@
         public abstract void getDeferredJobsLineLocked(StringBuilder sb, int which);
 
         public static abstract class Sensor {
+
+            @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+            public Sensor() {}
+
             /*
              * FIXME: it's not correct to use this magic value because it
              * could clash with a sensor handle (which are defined by
@@ -978,6 +995,9 @@
          */
         public static abstract class Proc {
 
+            @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+            public Proc() {}
+
             public static class ExcessivePower {
                 public static final int TYPE_WAKE = 1;
                 public static final int TYPE_CPU = 2;
@@ -1053,6 +1073,9 @@
          */
         public static abstract class Pkg {
 
+            @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+            public Pkg() {}
+
             /**
              * Returns information about all wakeup alarms that have been triggered for this
              * package.  The mapping keys are tag names for the alarms, the counter contains
@@ -1558,6 +1581,7 @@
      * Battery history record.
      */
     public static final class HistoryItem {
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         public HistoryItem next;
 
         // The time of this event in milliseconds, as per SystemClock.elapsedRealtime().
@@ -1875,6 +1899,7 @@
             numReadInts += (src.dataPosition()-start)/4;
         }
 
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         public void clear() {
             time = 0;
             cmd = CMD_NULL;
@@ -1895,12 +1920,14 @@
             eventTag = null;
         }
 
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         public void setTo(HistoryItem o) {
             time = o.time;
             cmd = o.cmd;
             setToCommon(o);
         }
 
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         public void setTo(long time, byte cmd, HistoryItem o) {
             this.time = time;
             this.cmd = cmd;
@@ -1956,6 +1983,7 @@
                     && currentTime == o.currentTime;
         }
 
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         public boolean same(HistoryItem o) {
             if (!sameNonEvent(o) || eventCode != o.eventCode) {
                 return false;
@@ -2338,6 +2366,7 @@
      *
      * {@hide}
      */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public abstract long getMobileRadioActiveTime(long elapsedRealtimeUs, int which);
 
     /**
@@ -2698,6 +2727,7 @@
     public static final int NETWORK_WIFI_BG_TX_DATA = 9;
     public static final int NUM_NETWORK_ACTIVITY_TYPES = NETWORK_WIFI_BG_TX_DATA + 1;
 
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public abstract long getNetworkActivityBytes(int type, int which);
     public abstract long getNetworkActivityPackets(int type, int which);
 
diff --git a/core/java/android/os/CancellationSignal.java b/core/java/android/os/CancellationSignal.java
index e8053d5..99fb998 100644
--- a/core/java/android/os/CancellationSignal.java
+++ b/core/java/android/os/CancellationSignal.java
@@ -18,13 +18,19 @@
 
 import android.os.ICancellationSignal;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 /**
  * Provides the ability to cancel an operation in progress.
  */
 public final class CancellationSignal {
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private boolean mIsCanceled;
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private OnCancelListener mOnCancelListener;
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private ICancellationSignal mRemote;
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private boolean mCancelInProgress;
 
     /**
@@ -152,6 +158,7 @@
         }
     }
 
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private void waitForCancelFinishedLocked() {
         while (mCancelInProgress) {
             try {
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index e1d605e..185693e 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -47,6 +47,7 @@
     void wakeUp(long time, int reason, String details, String opPackageName);
     @UnsupportedAppUsage
     void goToSleep(long time, int reason, int flags);
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void nap(long time);
     @UnsupportedAppUsage
     boolean isInteractive();
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index dbe3c93..e1b5542 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -3148,6 +3148,7 @@
     // Cache of previously looked up CREATOR.createFromParcel() methods for
     // particular classes.  Keys are the names of the classes, values are
     // Method objects.
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static final HashMap<ClassLoader,HashMap<String,Parcelable.Creator<?>>>
         mCreators = new HashMap<>();
 
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 8355e08..2a4576a 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -581,12 +581,16 @@
     public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
         if (data == null) return null;
         MemoryFile file = new MemoryFile(name, data.length);
-        if (data.length > 0) {
-            file.writeBytes(data, 0, 0, data.length);
+        try {
+            if (data.length > 0) {
+                file.writeBytes(data, 0, 0, data.length);
+            }
+            file.deactivate();
+            FileDescriptor fd = file.getFileDescriptor();
+            return fd != null ? ParcelFileDescriptor.dup(fd) : null;
+        } finally {
+            file.close();
         }
-        file.deactivate();
-        FileDescriptor fd = file.getFileDescriptor();
-        return fd != null ? ParcelFileDescriptor.dup(fd) : null;
     }
 
     /**
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 535d887..7ea2621 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -824,6 +824,7 @@
     final Context mContext;
     @UnsupportedAppUsage
     final IPowerManager mService;
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     final Handler mHandler;
 
     IThermalService mThermalService;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b535e8d..30e5959 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -999,6 +999,7 @@
      * your own log, or the Android Illuminati will find you some night and
      * beat you up.
      */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static final native void sendSignalQuiet(int pid, int signal);
     
     /** @hide */
diff --git a/core/java/android/os/Registrant.java b/core/java/android/os/Registrant.java
index 8fb123a..572b975 100644
--- a/core/java/android/os/Registrant.java
+++ b/core/java/android/os/Registrant.java
@@ -114,6 +114,7 @@
         }
     }
 
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public Handler
     getHandler()
     {
diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java
index 6e562ff..e9bc637 100644
--- a/core/java/android/os/RegistrantList.java
+++ b/core/java/android/os/RegistrantList.java
@@ -70,6 +70,7 @@
         return registrants.size();
     }
 
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public synchronized Object
     get(int index)
     {
diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java
index 047ba1d..da58d0f 100644
--- a/core/java/android/os/RemoteCallback.java
+++ b/core/java/android/os/RemoteCallback.java
@@ -21,6 +21,8 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 /**
  * @hide
  */
@@ -33,6 +35,7 @@
     }
 
     private final OnResultListener mListener;
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private final Handler mHandler;
     private final IRemoteCallback mCallback;
 
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index b377e8d..6165146 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -123,6 +123,7 @@
             IBinder binder = callback.asBinder();
             try {
                 Callback cb = new Callback(callback, cookie);
+                unregister(callback);
                 binder.linkToDeath(cb, 0);
                 mCallbacks.put(binder, cb);
                 return true;
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index a7edb5e..cdae72e 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -88,12 +88,17 @@
 
     @UnsupportedAppUsage
     private static native String native_get(String key);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native String native_get(String key, String def);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native int native_get_int(String key, int def);
     @UnsupportedAppUsage
     private static native long native_get_long(String key, long def);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native boolean native_get_boolean(String key, boolean def);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native void native_set(String key, String def);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native void native_add_change_callback();
     private static native void native_report_sysprop_change();
 
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index d70ba99..4e17f7e 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -354,6 +354,7 @@
      * components -- user, app, isolated, etc.
      * @hide
      */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static void formatUid(PrintWriter pw, int uid) {
         if (uid < Process.FIRST_APPLICATION_UID) {
             pw.print(uid);
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 1f6c3cc..2e3b000 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -221,4 +221,7 @@
      */
     public abstract boolean isSettingRestrictedForUser(String setting, int userId, String value,
             int callingUid);
+
+    /** @return a specific user restriction that's in effect currently. */
+    public abstract boolean hasUserRestriction(String restriction, int userId);
 }
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 0b4a561..114de23 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -39,14 +39,17 @@
      * The WorkSource object itself is not thread safe, but we need to
      * hold sTmpWorkSource lock while working with these statics.
      */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     static final WorkSource sTmpWorkSource = new WorkSource(0);
     /**
      * For returning newbie work from a modification operation.
      */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     static WorkSource sNewbWork;
     /**
      * For returning gone work form a modification operation.
      */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     static WorkSource sGoneWork;
 
     /**
@@ -619,6 +622,7 @@
         return changed;
     }
 
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) {
         if (mNames == null && other.mNames == null) {
             return updateUidsLocked(other, set, returnNewbs);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5308cd3..7df1ebe 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5959,6 +5959,18 @@
         public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED;
 
         /**
+         * Indicates whether a DPC has been downloaded during provisioning.
+         *
+         * <p>Type: int (0 for false, 1 for true)
+         *
+         * <p>If this is true, then any attempts to begin setup again should result in factory reset
+         *
+         * @hide
+         */
+        public static final String MANAGED_PROVISIONING_DPC_DOWNLOADED =
+                "managed_provisioning_dpc_downloaded";
+
+        /**
          * Indicates whether the current user has completed setup via the setup wizard.
          * <p>
          * Type: int (0 for false, 1 for true)
diff --git a/core/java/android/service/carrier/ICarrierMessagingService.aidl b/core/java/android/service/carrier/ICarrierMessagingService.aidl
index 2d96c3d..c4dfb57 100644
--- a/core/java/android/service/carrier/ICarrierMessagingService.aidl
+++ b/core/java/android/service/carrier/ICarrierMessagingService.aidl
@@ -36,6 +36,7 @@
      * @param subId SMS subscription ID of the SIM
      * @param callback the callback to notify upon completion
      */
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void filterSms(
         in MessagePdu pdu, String format, int destPort, int subId,
         in ICarrierMessagingCallback callback);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 60dbf84..e784ad3 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -196,7 +196,6 @@
         final WindowManager.LayoutParams mLayout
                 = new WindowManager.LayoutParams();
         IWindowSession mSession;
-        InputChannel mInputChannel;
 
         final Object mLock = new Object();
         boolean mOffsetMessageEnqueued;
@@ -819,11 +818,11 @@
                         mLayout.setTitle(WallpaperService.this.getClass().getName());
                         mLayout.windowAnimations =
                                 com.android.internal.R.style.Animation_Wallpaper;
-                        mInputChannel = new InputChannel();
+                        InputChannel inputChannel = new InputChannel();
 
                         if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
                                 mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets,
-                                mOutsets, mDisplayCutout, mInputChannel,
+                                mOutsets, mDisplayCutout, inputChannel,
                                 mInsetsState) < 0) {
                             Log.w(TAG, "Failed to add window while updating wallpaper surface.");
                             return;
@@ -831,7 +830,7 @@
                         mCreated = true;
 
                         mInputEventReceiver = new WallpaperInputEventReceiver(
-                                mInputChannel, Looper.myLooper());
+                                inputChannel, Looper.myLooper());
                     }
 
                     mSurfaceHolder.mSurfaceLock.lock();
@@ -1267,13 +1266,6 @@
                 }
                 mSurfaceHolder.mSurface.release();
                 mCreated = false;
-
-                // Dispose the input channel after removing the window so the Window Manager
-                // doesn't interpret the input channel being closed as an abnormal termination.
-                if (mInputChannel != null) {
-                    mInputChannel.dispose();
-                    mInputChannel = null;
-                }
             }
         }
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b347a78..bb9867a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -151,6 +151,7 @@
     float getCurrentAnimatorScale();
 
     // For testing
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void setInTouchMode(boolean showFocus);
 
     // For StrictMode flashing a red border on violations from the UI
@@ -158,6 +159,7 @@
     // Manager uses that to determine whether or not the red border should
     // actually be shown.  (it will be ignored that pid doesn't have windows
     // on screen)
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void showStrictModeViolation(boolean on);
 
     // Proxy to set the system property for whether the flashing
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 7260a65..ed8492e 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -102,7 +102,11 @@
             nativeDispose(mReceiverPtr);
             mReceiverPtr = 0;
         }
-        mInputChannel = null;
+
+        if (mInputChannel != null) {
+            mInputChannel.dispose();
+            mInputChannel = null;
+        }
         mMessageQueue = null;
     }
 
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index bff3a1d..bd865c0 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1471,6 +1471,10 @@
     @UnsupportedAppUsage
     private static final int HISTORY_CURRENT = -0x80000000;
 
+    // This is essentially the same as native AMOTION_EVENT_INVALID_CURSOR_POSITION as they're all
+    // NaN and we use isnan() everywhere to check validity.
+    private static final float INVALID_CURSOR_POSITION = Float.NaN;
+
     private static final int MAX_RECYCLED = 10;
     private static final Object gRecyclerLock = new Object();
     private static int gRecyclerUsed;
@@ -1590,6 +1594,12 @@
     @CriticalNative
     private static native float nativeGetYPrecision(long nativePtr);
     @CriticalNative
+    private static native float nativeGetXCursorPosition(long nativePtr);
+    @CriticalNative
+    private static native float nativeGetYCursorPosition(long nativePtr);
+    @CriticalNative
+    private static native void nativeSetCursorPosition(long nativePtr, float x, float y);
+    @CriticalNative
     private static native long nativeGetDownTimeNanos(long nativePtr);
     @CriticalNative
     private static native void nativeSetDownTimeNanos(long nativePtr, long downTime);
@@ -1674,12 +1684,11 @@
             float xPrecision, float yPrecision, int deviceId,
             int edgeFlags, int source, int displayId, int flags) {
         MotionEvent ev = obtain();
-        ev.mNativePtr = nativeInitialize(ev.mNativePtr,
-                deviceId, source, displayId, action, flags, edgeFlags, metaState, buttonState,
-                CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision,
+        final boolean success = ev.initialize(deviceId, source, displayId, action, flags, edgeFlags,
+                metaState, buttonState, CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision,
                 downTime * NS_PER_MS, eventTime * NS_PER_MS,
                 pointerCount, pointerProperties, pointerCoords);
-        if (ev.mNativePtr == 0) {
+        if (!success) {
             Log.e(TAG, "Could not initialize MotionEvent");
             ev.recycle();
             return null;
@@ -1859,8 +1868,7 @@
             pc[0].pressure = pressure;
             pc[0].size = size;
 
-            ev.mNativePtr = nativeInitialize(ev.mNativePtr,
-                    deviceId, source, displayId,
+            ev.initialize(deviceId, source, displayId,
                     action, 0, edgeFlags, metaState, 0 /*buttonState*/, CLASSIFICATION_NONE,
                     0, 0, xPrecision, yPrecision,
                     downTime * NS_PER_MS, eventTime * NS_PER_MS,
@@ -1958,6 +1966,22 @@
         return ev;
     }
 
+    private boolean initialize(int deviceId, int source, int displayId, int action, int flags,
+            int edgeFlags, int metaState, int buttonState, @Classification int classification,
+            float xOffset, float yOffset, float xPrecision, float yPrecision,
+            long downTimeNanos, long eventTimeNanos,
+            int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords) {
+        mNativePtr = nativeInitialize(mNativePtr, deviceId, source, displayId, action, flags,
+                edgeFlags, metaState, buttonState, classification, xOffset, yOffset,
+                xPrecision, yPrecision, downTimeNanos, eventTimeNanos, pointerCount, pointerIds,
+                pointerCoords);
+        if (mNativePtr == 0) {
+            return false;
+        }
+        updateCursorPosition();
+        return true;
+    }
+
     /** @hide */
     @Override
     @UnsupportedAppUsage
@@ -2015,7 +2039,11 @@
     /** {@inheritDoc} */
     @Override
     public final void setSource(int source) {
+        if (source == getSource()) {
+            return;
+        }
         nativeSetSource(mNativePtr, source);
+        updateCursorPosition();
     }
 
     /** @hide */
@@ -2670,6 +2698,39 @@
     }
 
     /**
+     * Returns the x coordinate of mouse cursor position when this event is
+     * reported. This value is only valid if {@link #getSource()} returns
+     * {@link InputDevice#SOURCE_MOUSE}.
+     *
+     * @hide
+     */
+    public float getXCursorPosition() {
+        return nativeGetXCursorPosition(mNativePtr);
+    }
+
+    /**
+     * Returns the y coordinate of mouse cursor position when this event is
+     * reported. This value is only valid if {@link #getSource()} returns
+     * {@link InputDevice#SOURCE_MOUSE}.
+     *
+     * @hide
+     */
+    public float getYCursorPosition() {
+        return nativeGetYCursorPosition(mNativePtr);
+    }
+
+    /**
+     * Sets cursor position to given coordinates. The coordinate in parameters should be after
+     * offsetting. In other words, the effect of this function is {@link #getXCursorPosition()} and
+     * {@link #getYCursorPosition()} will return the same value passed in the parameters.
+     *
+     * @hide
+     */
+    private void setCursorPosition(float x, float y) {
+        nativeSetCursorPosition(mNativePtr, x, y);
+    }
+
+    /**
      * Returns the number of historical points in this event.  These are
      * movements that have occurred between this event and the previous event.
      * This only applies to ACTION_MOVE events -- all other actions will have
@@ -3305,8 +3366,7 @@
                 pc[i].x = clamp(pc[i].x, left, right);
                 pc[i].y = clamp(pc[i].y, top, bottom);
             }
-            ev.mNativePtr = nativeInitialize(ev.mNativePtr,
-                    nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr),
+            ev.initialize(nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr),
                     nativeGetDisplayId(mNativePtr),
                     nativeGetAction(mNativePtr), nativeGetFlags(mNativePtr),
                     nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr),
@@ -3399,8 +3459,7 @@
 
                 final long eventTimeNanos = nativeGetEventTimeNanos(mNativePtr, historyPos);
                 if (h == 0) {
-                    ev.mNativePtr = nativeInitialize(ev.mNativePtr,
-                            nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr),
+                    ev.initialize(nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr),
                             nativeGetDisplayId(mNativePtr),
                             newAction, nativeGetFlags(mNativePtr),
                             nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr),
@@ -3417,6 +3476,38 @@
         }
     }
 
+    /**
+     * Calculate new cursor position for events from mouse. This is used to split, clamp and inject
+     * events.
+     *
+     * <p>If the source is mouse, it sets cursor position to the centroid of all pointers because
+     * InputReader maps multiple fingers on a touchpad to locations around cursor position in screen
+     * coordinates so that the mouse cursor is at the centroid of all pointers.
+     *
+     * <p>If the source is not mouse it sets cursor position to NaN.
+     */
+    private void updateCursorPosition() {
+        if (getSource() != InputDevice.SOURCE_MOUSE) {
+            setCursorPosition(INVALID_CURSOR_POSITION, INVALID_CURSOR_POSITION);
+            return;
+        }
+
+        float x = 0;
+        float y = 0;
+
+        final int pointerCount = getPointerCount();
+        for (int i = 0; i < pointerCount; ++i) {
+            x += getX(i);
+            y += getY(i);
+        }
+
+        // If pointer count is 0, divisions below yield NaN, which is an acceptable result for this
+        // corner case.
+        x /= pointerCount;
+        y /= pointerCount;
+        setCursorPosition(x, y);
+    }
+
     @Override
     public String toString() {
         StringBuilder msg = new StringBuilder();
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1a66898..90e69f3 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -38,6 +38,7 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.view.SurfaceCallbackHelper;
 
@@ -118,7 +119,7 @@
     boolean mDrawFinished = false;
 
     final Rect mScreenRect = new Rect();
-    SurfaceSession mSurfaceSession;
+    private final SurfaceSession mSurfaceSession = new SurfaceSession();
 
     SurfaceControl mSurfaceControl;
     // In the case of format changes we switch out the surface in-place
@@ -193,6 +194,7 @@
 
     private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
     private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+    private int mParentSurfaceGenerationId;
 
     public SurfaceView(Context context) {
         this(context, null);
@@ -644,13 +646,12 @@
         }
     }
 
-    private void updateBackgroundVisibilityInTransaction(SurfaceControl viewRoot) {
+    private void updateBackgroundVisibilityInTransaction() {
         if (mBackgroundControl == null) {
             return;
         }
         if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
             mBackgroundControl.show();
-            mBackgroundControl.setRelativeLayer(viewRoot, Integer.MIN_VALUE);
         } else {
             mBackgroundControl.hide();
         }
@@ -742,11 +743,24 @@
                 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
 
                 if (creating) {
-                    viewRoot.createBoundsSurface(mSubLayer);
-                    mSurfaceSession = new SurfaceSession();
                     mDeferredDestroySurfaceControl = mSurfaceControl;
 
                     updateOpaqueFlag();
+                    // SurfaceView hierarchy
+                    // ViewRootImpl surface
+                    //   - bounds layer (crops all child surfaces to parent surface insets)
+                    //     - SurfaceView surface (drawn relative to ViewRootImpl surface)
+                    //     - Background color layer (drawn behind all SurfaceView surfaces)
+                    //
+                    // The bounds layer is used to crop the surface view so it does not draw into
+                    // the parent surface inset region. Since there can be multiple surface views
+                    // below or above the parent surface, one option is to create multiple bounds
+                    // layer for each z order. The other option, the one implement is to create
+                    // a single bounds layer and set z order for each child surface relative to the
+                    // parent surface.
+                    // When creating the surface view, we parent it to the bounds layer and then
+                    // set the relative z order. When the parent surface changes, we have to
+                    // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback.
                     final String name = "SurfaceView - " + viewRoot.getTitle().toString();
 
                     mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
@@ -754,7 +768,7 @@
                         .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
                         .setBufferSize(mSurfaceWidth, mSurfaceHeight)
                         .setFormat(mFormat)
-                        .setParent(viewRoot.getSurfaceControl())
+                        .setParent(viewRoot.getBoundsLayer())
                         .setFlags(mSurfaceFlags)
                         .build();
                     mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
@@ -779,14 +793,23 @@
 
                     SurfaceControl.openTransaction();
                     try {
-                        mSurfaceControl.setLayer(mSubLayer);
+                        // If we are creating the surface control or the parent surface has not
+                        // changed, then set relative z. Otherwise allow the parent
+                        // SurfaceChangedCallback to update the relative z. This is needed so that
+                        // we do not change the relative z before the server is ready to swap the
+                        // parent surface.
+                        if (creating || (mParentSurfaceGenerationId
+                                == viewRoot.mSurface.getGenerationId())) {
+                            SurfaceControl.mergeToGlobalTransaction(updateRelativeZ());
+                        }
+                        mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
 
                         if (mViewVisibility) {
                             mSurfaceControl.show();
                         } else {
                             mSurfaceControl.hide();
                         }
-                        updateBackgroundVisibilityInTransaction(viewRoot.getSurfaceControl());
+                        updateBackgroundVisibilityInTransaction();
                         if (mUseAlpha) {
                             mSurfaceControl.setAlpha(alpha);
                             mSurfaceAlpha = alpha;
@@ -1369,11 +1392,22 @@
     }
 
     /**
-     * Called when a valid ViewRootImpl surface is replaced by another valid surface.
+     * Called when a valid ViewRootImpl surface is replaced by another valid surface. In this
+     * case update relative z to the new parent surface.
      * @hide
      */
     @Override
-    public void surfaceReplaced(SurfaceControl.Transaction t) {
+    public void surfaceReplaced(Transaction t) {
+        if (mSurfaceControl != null && mBackgroundControl != null) {
+            t.merge(updateRelativeZ());
+        }
+    }
 
+    private Transaction updateRelativeZ() {
+        Transaction t = new Transaction();
+        SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl();
+        t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE);
+        t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer);
+        return t;
     }
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index a01e15e..aa29c5f 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -28,6 +28,7 @@
 import android.graphics.RenderNode;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.util.Log;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
 import android.view.animation.AnimationUtils;
@@ -674,11 +675,11 @@
 
         int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
         if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
-            setEnabled(false);
-            attachInfo.mViewRootImpl.mSurface.release();
-            // Invalidate since we failed to draw. This should fetch a Surface
-            // if it is still needed or do nothing if we are no longer drawing
-            attachInfo.mViewRootImpl.invalidate();
+            Log.w("OpenGLRenderer", "Surface lost, forcing relayout");
+            // We lost our surface. For a relayout next frame which should give us a new
+            // surface from WindowManager, which hopefully will work.
+            attachInfo.mViewRootImpl.mForceNextWindowRelayout = true;
+            attachInfo.mViewRootImpl.requestLayout();
         }
         if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) {
             attachInfo.mViewRootImpl.invalidate();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 45309bb..1779a80 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8501,7 +8501,7 @@
      * </ul>
      *
      * <p>It's also recommended to set the following properties - the more properties the structure
-     * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly
+     * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly
      * using the structure:
      *
      * <ul>
@@ -11074,6 +11074,13 @@
      *
      * <p>Do not modify the provided list after this method is called.</p>
      *
+     * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the
+     * exclusions it takes into account. The limit does not apply while the navigation
+     * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the
+     * {@link android.inputmethodservice.InputMethodService input method} and
+     * {@link Intent#CATEGORY_HOME home activity}.
+     * </p>
+     *
      * @param rects A list of precision gesture regions that this view needs to function correctly
      */
     public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 354cc96..3a51eaa 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -399,7 +399,6 @@
 
     @UnsupportedAppUsage
     final View.AttachInfo mAttachInfo;
-    InputChannel mInputChannel;
     InputQueue.Callback mInputQueueCallback;
     InputQueue mInputQueue;
     @UnsupportedAppUsage
@@ -484,15 +483,13 @@
      */
     private final Transaction mSurfaceChangedTransaction = new Transaction();
     /**
-     * Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds
-     * are set to the parent's bounds adjusted for surface insets. This surface is created when
-     * {@link ViewRootImpl#createBoundsSurface(int)} is called.
-     * By parenting to this bounds surface, child surfaces can ensure they do not draw into the
-     * surface inset regions set by the parent window.
+     * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to
+     * the surface insets. This surface is created only if a client requests it via {@link
+     * #getBoundsLayer()}. By parenting to this bounds surface, child surfaces can ensure they do
+     * not draw into the surface inset region set by the parent window.
      */
-    public final Surface mBoundsSurface = new Surface();
-    private SurfaceSession mSurfaceSession;
-    private SurfaceControl mBoundsSurfaceControl;
+    private SurfaceControl mBoundsLayer;
+    private final SurfaceSession mSurfaceSession = new SurfaceSession();
     private final Transaction mTransaction = new Transaction();
 
     @UnsupportedAppUsage
@@ -884,9 +881,10 @@
                 // manager, to make sure we do the relayout before receiving
                 // any other events from the system.
                 requestLayout();
+                InputChannel inputChannel = null;
                 if ((mWindowAttributes.inputFeatures
                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
-                    mInputChannel = new InputChannel();
+                    inputChannel = new InputChannel();
                 }
                 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                         & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
@@ -897,14 +895,14 @@
                     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                             getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
-                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
+                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, inputChannel,
                             mTempInsets);
                     setFrame(mTmpFrame);
                 } catch (RemoteException e) {
                     mAdded = false;
                     mView = null;
                     mAttachInfo.mRootView = null;
-                    mInputChannel = null;
+                    inputChannel = null;
                     mFallbackEventHandler.setView(null);
                     unscheduleTraversals();
                     setAccessibilityFocus(null, null);
@@ -980,12 +978,12 @@
                     mInputQueueCallback =
                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
                 }
-                if (mInputChannel != null) {
+                if (inputChannel != null) {
                     if (mInputQueueCallback != null) {
                         mInputQueue = new InputQueue();
                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
                     }
-                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
+                    mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                             Looper.myLooper());
                 }
 
@@ -1614,66 +1612,55 @@
         }
     }
 
-
     /**
-     * Creates a surface as a child of {@code mSurface} with the same bounds as its parent and
-     * crop bounds set to the parent's bounds adjusted for surface insets.
+     * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the
+     * surface insets. If the layer does not exist, it is created.
      *
-     * @param zOrderLayer Z order relative to the parent surface.
+     * <p>Parenting to this layer will ensure that its children are cropped by the view's surface
+     * insets.
      */
-    public void createBoundsSurface(int zOrderLayer) {
-        if (mSurfaceSession == null) {
-            mSurfaceSession = new SurfaceSession();
+    public SurfaceControl getBoundsLayer() {
+        if (mBoundsLayer == null) {
+            mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
+                    .setContainerLayer()
+                    .setName("Bounds for - " + getTitle().toString())
+                    .setParent(mSurfaceControl)
+                    .build();
+            setBoundsLayerCrop();
+            mTransaction.show(mBoundsLayer).apply();
         }
-        if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) {
-            return; // surface control for bounds surface already exists.
-        }
-
-        mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
-                .setName("Bounds for - " + getTitle().toString())
-                .setParent(mSurfaceControl)
-                .build();
-
-        setBoundsSurfaceCrop();
-        mTransaction.setLayer(mBoundsSurfaceControl, zOrderLayer)
-                    .show(mBoundsSurfaceControl)
-                    .apply();
-        mBoundsSurface.copyFrom(mBoundsSurfaceControl);
+        return mBoundsLayer;
     }
 
-    private void setBoundsSurfaceCrop() {
+    private void setBoundsLayerCrop() {
         // mWinFrame is already adjusted for surface insets. So offset it and use it as
         // the cropping bounds.
         mTempBoundsRect.set(mWinFrame);
         mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left,
                 mWindowAttributes.surfaceInsets.top);
-        mTransaction.setWindowCrop(mBoundsSurfaceControl, mTempBoundsRect);
+        mTransaction.setWindowCrop(mBoundsLayer, mTempBoundsRect);
     }
 
     /**
-     * Called after window layout to update the bounds surface. If the surface insets have
-     * changed or the surface has resized, update the bounds surface.
+     * Called after window layout to update the bounds surface. If the surface insets have changed
+     * or the surface has resized, update the bounds surface.
      */
-    private void updateBoundsSurface() {
-        if (mBoundsSurfaceControl != null && mSurface.isValid()) {
-            setBoundsSurfaceCrop();
-            mTransaction.deferTransactionUntilSurface(mBoundsSurfaceControl,
+    private void updateBoundsLayer() {
+        if (mBoundsLayer != null) {
+            setBoundsLayerCrop();
+            mTransaction.deferTransactionUntilSurface(mBoundsLayer,
                     mSurface, mSurface.getNextFrameNumber())
                     .apply();
         }
     }
 
     private void destroySurface() {
+        if (mBoundsLayer != null) {
+            mBoundsLayer.release();
+            mBoundsLayer = null;
+        }
         mSurface.release();
         mSurfaceControl.release();
-
-        mSurfaceSession = null;
-
-        if (mBoundsSurfaceControl != null) {
-            mTransaction.remove(mBoundsSurfaceControl).apply();
-            mBoundsSurface.release();
-            mBoundsSurfaceControl = null;
-        }
     }
 
     /**
@@ -2649,8 +2636,8 @@
             maybeHandleWindowMove(frame);
         }
 
-        if (surfaceSizeChanged) {
-            updateBoundsSurface();
+        if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
+            updateBoundsLayer();
         }
 
         final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
@@ -4388,13 +4375,6 @@
         } catch (RemoteException e) {
         }
 
-        // Dispose the input channel after removing the window so the Window Manager
-        // doesn't interpret the input channel being closed as an abnormal termination.
-        if (mInputChannel != null) {
-            mInputChannel.dispose();
-            mInputChannel = null;
-        }
-
         mDisplayManager.unregisterDisplayListener(mDisplayListener);
 
         unscheduleTraversals();
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 6efb6f3..5f3ce33 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -228,6 +228,16 @@
     public abstract void setHint(CharSequence hint);
 
     /**
+     * Sets the identifier used to set the hint associated with this view.
+     *
+     * <p>Should only be set when the node is used for autofill purposes - it will be ignored
+     * when used for Assist.
+     */
+    public void setHintIdEntry(@NonNull String entryName) {
+        Preconditions.checkNotNull(entryName);
+    }
+
+    /**
      * Retrieve the last {@link #setText(CharSequence)}.
      */
     public abstract CharSequence getText();
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 9340b71..bcc6a55 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -35,6 +35,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.content.Intent;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.util.SparseArray;
@@ -644,6 +645,14 @@
      * {@link View#setSystemGestureExclusionRects} outside of the
      * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}.
      *
+     * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the
+     * exclusions it takes into account. The limit does not apply while the navigation
+     * bar is {@link View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the
+     * {@link android.inputmethodservice.InputMethodService input method} and
+     * {@link Intent#CATEGORY_HOME home activity}.
+     * </p>
+     *
+     *
      * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
      * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
      *
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index 8d62454..0dd2587 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -81,6 +81,7 @@
     private static final long FLAGS_HAS_AUTOFILL_VALUE = 1L << 32;
     private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 33;
     private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 34;
+    private static final long FLAGS_HAS_HINT_ID_ENTRY = 1L << 35;
 
     /** Flags used to optimize what's written to the parcel */
     private long mFlags;
@@ -108,6 +109,7 @@
     private int mMaxEms = -1;
     private int mMaxLength = -1;
     private String mTextIdEntry;
+    private String mHintIdEntry;
     private @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
     private String[] mAutofillHints;
     private AutofillValue mAutofillValue;
@@ -195,6 +197,9 @@
         if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
             mAutofillOptions = parcel.readCharSequenceArray();
         }
+        if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) {
+            mHintIdEntry = parcel.readString();
+        }
     }
 
     /**
@@ -352,6 +357,11 @@
     }
 
     @Override
+    public String getHintIdEntry() {
+        return mHintIdEntry;
+    }
+
+    @Override
     public int getTextSelectionStart() {
         return mText != null ? mText.mTextSelectionStart : -1;
     }
@@ -512,6 +522,9 @@
         if (mAutofillOptions != null) {
             nodeFlags |= FLAGS_HAS_AUTOFILL_OPTIONS;
         }
+        if (mHintIdEntry != null) {
+            nodeFlags |= FLAGS_HAS_HINT_ID_ENTRY;
+        }
         parcel.writeLong(nodeFlags);
 
         if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
@@ -585,6 +598,9 @@
         if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
             parcel.writeCharSequenceArray(mAutofillOptions);
         }
+        if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) {
+            parcel.writeString(mHintIdEntry);
+        }
     }
 
     /** @hide */
@@ -783,7 +799,7 @@
         }
 
         @Override
-        public void setTextIdEntry(String entryName) {
+        public void setTextIdEntry(@NonNull String entryName) {
             mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
         }
 
@@ -793,6 +809,11 @@
         }
 
         @Override
+        public void setHintIdEntry(String entryName) {
+            mNode.mHintIdEntry = Preconditions.checkNotNull(entryName);
+        }
+
+        @Override
         public CharSequence getText() {
             return mNode.getText();
         }
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index e1a9898..a26243c 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -480,7 +480,7 @@
      * matter what user ID the calling process has.
      *
      * <p>Note: This field will be silently ignored when
-     * {@link android.view.inputmethod.InputMethodSystemProperty#MULTI_CLIENT_IME_ENABLED} is
+     * {@link com.android.server.inputmethod.InputMethodSystemProperty#MULTI_CLIENT_IME_ENABLED} is
      * {@code true}.</p>
      *
      * <p>Note also that pseudo handles such as {@link UserHandle#ALL} are not supported.</p>
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 80c728f..12ed4b9 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -410,6 +410,15 @@
     }
 
     /**
+     * Sets the id of this event's user.
+     * <p>
+     * Package-private for SystemTextClassifier's use.
+     */
+    void setUserId(@UserIdInt int userId) {
+        mUserId = userId;
+    }
+
+    /**
      * Returns the id of this event's user.
      * @hide
      */
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index b5f972a..a97c330 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -151,6 +151,7 @@
         Utils.checkMainThread();
 
         try {
+            event.setUserId(mUserId);
             mManagerService.onSelectionEvent(mSessionId, event);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Error reporting selection event.", e);
@@ -163,6 +164,12 @@
         Utils.checkMainThread();
 
         try {
+            final TextClassificationContext tcContext = event.getEventContext() == null
+                    ? new TextClassificationContext.Builder(mPackageName, WIDGET_TYPE_UNKNOWN)
+                            .build()
+                    : event.getEventContext();
+            tcContext.setUserId(mUserId);
+            event.setEventContext(tcContext);
             mManagerService.onTextClassifierEvent(mSessionId, event);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Error reporting textclassifier event.", e);
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index 57da829..a041296 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -139,7 +139,7 @@
     @Nullable
     private final String[] mEntityTypes;
     @Nullable
-    private final TextClassificationContext mEventContext;
+    private TextClassificationContext mEventContext;
     @Nullable
     private final String mResultId;
     private final int mEventIndex;
@@ -289,6 +289,15 @@
     }
 
     /**
+     * Sets the event context.
+     * <p>
+     * Package-private for SystemTextClassifier's use.
+     */
+    void setEventContext(@Nullable TextClassificationContext eventContext) {
+        mEventContext = eventContext;
+    }
+
+    /**
      * Returns the id of the text classifier result related to this event.
      */
     @Nullable
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index a46580d..18d4d69 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -464,7 +464,9 @@
      * Note that the feature will continue to be supported on older versions of
      * Android as before.
      *
-     * This function does not have any effect.
+     * @deprecated In Android O and afterwards, this function does not have
+     * any effect, the form data will be saved to platform's autofill service
+     * if applicable.
      */
     @Deprecated
     public abstract  void setSaveFormData(boolean save);
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 5091eea..ad35633 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -42,6 +42,8 @@
 import android.view.animation.LinearInterpolator;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.R;
+
 import java.lang.ref.WeakReference;
 
 @RemoteView
@@ -1241,14 +1243,40 @@
         info.setScrollable(getChildCount() > 1);
         if (isEnabled()) {
             if (getDisplayedChild() < getChildCount() - 1) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+                if (mStackMode == ITEMS_SLIDE_UP) {
+                    info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN);
+                } else {
+                    info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP);
+                }
             }
             if (getDisplayedChild() > 0) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
+                if (mStackMode == ITEMS_SLIDE_UP) {
+                    info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP);
+                } else {
+                    info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN);
+                }
             }
         }
     }
 
+    private boolean goForward() {
+        if (getDisplayedChild() < getChildCount() - 1) {
+            showNext();
+            return true;
+        }
+        return false;
+    }
+
+    private boolean goBackward() {
+        if (getDisplayedChild() > 0) {
+            showPrevious();
+            return true;
+        }
+        return false;
+    }
+
     /** @hide */
     @Override
     public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
@@ -1260,17 +1288,25 @@
         }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                if (getDisplayedChild() < getChildCount() - 1) {
-                    showNext();
-                    return true;
-                }
-            } return false;
+                return goForward();
+            }
             case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                if (getDisplayedChild() > 0) {
-                    showPrevious();
-                    return true;
+                return goBackward();
+            }
+            case R.id.accessibilityActionPageUp: {
+                if (mStackMode == ITEMS_SLIDE_UP) {
+                    return goBackward();
+                } else {
+                    return goForward();
                 }
-            } return false;
+            }
+            case R.id.accessibilityActionPageDown: {
+                if (mStackMode == ITEMS_SLIDE_UP) {
+                    return goForward();
+                } else {
+                    return goBackward();
+                }
+            }
         }
         return false;
     }
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 481704c..90cb1c8 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -46,7 +46,11 @@
  * page. The individual elements are typically controlled using this container object, rather than
  * setting values on the child elements themselves.
  *
+ * @deprecated new applications should use fragment APIs instead of this class:
+ * Use <a href="{@docRoot}guide/navigation/navigation-swipe-view">TabLayout and ViewPager</a>
+ * instead.
  */
+@Deprecated
 public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener {
 
     private static final int TABWIDGET_LOCATION_LEFT = 0;
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 4c67b08..434a799 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -53,7 +53,12 @@
  * @attr ref android.R.styleable#TabWidget_tabStripEnabled
  * @attr ref android.R.styleable#TabWidget_tabStripLeft
  * @attr ref android.R.styleable#TabWidget_tabStripRight
+ *
+ * @deprecated new applications should use fragment APIs instead of this class:
+ * Use <a href="{@docRoot}guide/navigation/navigation-swipe-view">TabLayout and ViewPager</a>
+ * instead.
  */
+@Deprecated
 public class TabWidget extends LinearLayout implements OnFocusChangeListener {
     private final Rect mBounds = new Rect();
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a4844ea..f997d68 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -918,6 +918,8 @@
     private boolean mTextSetFromXmlOrResourceId = false;
     // Resource id used to set the text.
     private @StringRes int mTextId = Resources.ID_NULL;
+    // Resource id used to set the hint.
+    private @StringRes int mHintId = Resources.ID_NULL;
     //
     // End of autofill-related attributes
 
@@ -1210,6 +1212,7 @@
                     break;
 
                 case com.android.internal.R.styleable.TextView_hint:
+                    mHintId = a.getResourceId(attr, Resources.ID_NULL);
                     hint = a.getText(attr);
                     break;
 
@@ -6446,6 +6449,7 @@
      */
     @android.view.RemotableViewMethod
     public final void setHint(@StringRes int resid) {
+        mHintId = resid;
         setHint(getContext().getResources().getText(resid));
     }
 
@@ -11598,6 +11602,16 @@
                 structure.setMaxTextLength(maxLength);
             }
         }
+        if (mHintId != Resources.ID_NULL) {
+            try {
+                structure.setHintIdEntry(getResources().getResourceEntryName(mHintId));
+            } catch (Resources.NotFoundException e) {
+                if (android.view.autofill.Helper.sVerbose) {
+                    Log.v(LOG_TAG, "onProvideAutofillStructure(): cannot set name for hint id "
+                            + mHintId + ": " + e.getMessage());
+                }
+            }
+        }
         structure.setHint(getHint());
         structure.setInputType(getInputType());
     }
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index ee4666f..7c50337 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -47,6 +47,13 @@
      */
     public static final String NAS_MAX_SUGGESTIONS = "nas_max_suggestions";
 
+    // Flags related to controls
+
+    /**
+     * (boolean) Wether to have split behavior when opening QS
+     */
+    public static final String QS_SPLIT_ENABLED = "qs_split_enabled";
+
     // Flags related to Smart Suggestions - these are read in SmartReplyConstants.
 
     /** (boolean) Whether to enable smart suggestions in notifications. */
@@ -194,6 +201,38 @@
     public static final String ASSIST_HANDLES_SHOW_WHEN_TAUGHT = "assist_handles_show_when_taught";
 
     /**
+     * (long) Duration per pixel, in milliseconds, of scrolling text at fast speed.
+     */
+    public static final String ASSIST_TRANSCRIPTION_DURATION_PER_PX_FAST =
+            "assist_transcription_duration_per_px_fast";
+
+    /**
+     * (long) Duration per pixel, in milliseconds, of scrolling text at regular speed.
+     */
+    public static final String ASSIST_TRANSCRIPTION_DURATION_PER_PX_REGULAR =
+            "assist_transcription_duration_per_px_regular";
+
+    /**
+     * (long) Duration, in milliseconds, over which text fades in.
+     */
+    public static final String ASSIST_TRANSCRIPTION_FADE_IN_DURATION =
+            "assist_transcription_fade_in_duration";
+
+    /**
+     * (long) Maximum total duration, in milliseconds, for a given transcription.
+     */
+    public static final String ASSIST_TRANSCRIPTION_MAX_DURATION =
+            "assist_transcription_max_duration";
+
+    /**
+     * (long) Minimum total duration, in milliseconds, for a given transcription.
+     */
+    public static final String ASSIST_TRANSCRIPTION_MIN_DURATION =
+            "assist_transcription_min_duration";
+
+    // Flags related to brightline falsing
+
+    /**
      * (bool) Whether to use the new BrightLineFalsingManager.
      */
     public static final String BRIGHTLINE_FALSING_MANAGER_ENABLED =
@@ -282,5 +321,6 @@
             "brightline_falsing_zigzag_y_secondary_deviance";
 
 
-    private SystemUiDeviceConfigFlags() { }
+    private SystemUiDeviceConfigFlags() {
+    }
 }
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index d53fada..e09e0e6 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -76,28 +76,13 @@
         boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();
 
         if (useSystemSuspend) {
-            WakeLockInfo[] wlStats = null;
-            if (mSuspendControlService == null) {
-                try {
-                    mSuspendControlService = ISuspendControlService.Stub.asInterface(
-                        ServiceManager.getServiceOrThrow("suspend_control"));
-                } catch (ServiceNotFoundException e) {
-                    Slog.wtf(TAG, "Required service suspend_control not available", e);
-                    return null;
-                }
-            }
-
-            try {
-                wlStats = mSuspendControlService.getWakeLockStats();
-                updateVersion(staleStats);
-                updateWakelockStats(wlStats, staleStats);
-            } catch (RemoteException e) {
-                Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
+            // Get both kernel and native wakelock stats from SystemSuspend
+            updateVersion(staleStats);
+            if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
+                Slog.w(TAG, "Failed to get wakelock stats from SystemSuspend");
                 return null;
             }
-
             return removeOldStats(staleStats);
-
         } else {
             byte[] buffer = new byte[32*1024];
             int len = 0;
@@ -153,12 +138,44 @@
             }
 
             updateVersion(staleStats);
+            // Get native wakelock stats from SystemSuspend
+            if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
+                Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
+            }
+            // Get kernel wakelock stats
             parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
             return removeOldStats(staleStats);
         }
     }
 
     /**
+     * On success, returns the updated stats from SystemSupend, else returns null.
+     */
+    private KernelWakelockStats getWakelockStatsFromSystemSuspend(
+            final KernelWakelockStats staleStats) {
+        WakeLockInfo[] wlStats = null;
+        if (mSuspendControlService == null) {
+            try {
+                mSuspendControlService = ISuspendControlService.Stub.asInterface(
+                    ServiceManager.getServiceOrThrow("suspend_control"));
+            } catch (ServiceNotFoundException e) {
+                Slog.wtf(TAG, "Required service suspend_control not available", e);
+                return null;
+            }
+        }
+
+        try {
+            wlStats = mSuspendControlService.getWakeLockStats();
+            updateWakelockStats(wlStats, staleStats);
+        } catch (RemoteException e) {
+            Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
+            return null;
+        }
+
+        return staleStats;
+    }
+
+    /**
      * Updates statleStats with stats from  SystemSuspend.
      * @param staleStats Existing object to update.
      * @return the updated stats.
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index c46f867..2779be6 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -297,10 +297,10 @@
 
     private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition,
             int bottomPosition, int dividerMax) {
-        maybeAddTarget(topPosition, topPosition - mInsets.top);
+        maybeAddTarget(topPosition, topPosition - getStartInset());
         addMiddleTarget(isHorizontalDivision);
-        maybeAddTarget(bottomPosition, dividerMax - mInsets.bottom
-                - (bottomPosition + mDividerSize));
+        maybeAddTarget(bottomPosition,
+                dividerMax - getEndInset() - (bottomPosition + mDividerSize));
     }
 
     private void addFixedDivisionTargets(boolean isHorizontalDivision, int dividerMax) {
diff --git a/core/java/com/android/internal/preference/YesNoPreference.java b/core/java/com/android/internal/preference/YesNoPreference.java
index 7abf416..46d14a1 100644
--- a/core/java/com/android/internal/preference/YesNoPreference.java
+++ b/core/java/com/android/internal/preference/YesNoPreference.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.preference;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Parcel;
@@ -40,6 +41,7 @@
         this(context, attrs, defStyleAttr, 0);
     }
 
+    @UnsupportedAppUsage
     public YesNoPreference(Context context, AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.yesNoPreferenceStyle);
     }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index c715577..cf0394d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -58,7 +58,7 @@
 
     void topAppWindowChanged(int displayId, boolean menuVisible);
     void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
-            boolean showImeSwitcher);
+            boolean showImeSwitcher, boolean isMultiClientImeEnabled);
     void setWindowState(int display, int window, int state);
 
     void showRecentApps(boolean triggeredFromAltTab);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 598c391..85ae18e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -49,7 +49,7 @@
     @UnsupportedAppUsage
     void removeIcon(String slot);
     void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
-            boolean showImeSwitcher);
+            boolean showImeSwitcher, boolean isMultiClientImeEnabled);
     void expandSettingsPanel(String subPanel);
 
     // ---- Methods below are for use by the status bar policy services ----
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index b73ecd1..821022f 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -320,23 +320,57 @@
         return array;
     }
 
+    /**
+     * Combine multiple arrays into a single array.
+     *
+     * @param kind The class of the array elements
+     * @param arrays The arrays to combine
+     * @param <T> The class of the array elements (inferred from kind).
+     * @return A single array containing all the elements of the parameter arrays.
+     */
     @SuppressWarnings("unchecked")
-    public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[] a, @Nullable T[] b) {
-        final int an = (a != null) ? a.length : 0;
-        final int bn = (b != null) ? b.length : 0;
-        if (an == 0 && bn == 0) {
-            if (kind == String.class) {
-                return (T[]) EmptyArray.STRING;
-            } else if (kind == Object.class) {
-                return (T[]) EmptyArray.OBJECT;
-            }
+    public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) {
+        if (arrays == null || arrays.length == 0) {
+            return createEmptyArray(kind);
         }
-        final T[] res = (T[]) Array.newInstance(kind, an + bn);
-        if (an > 0) System.arraycopy(a, 0, res, 0, an);
-        if (bn > 0) System.arraycopy(b, 0, res, an, bn);
-        return res;
+
+        int totalLength = 0;
+        for (T[] item : arrays) {
+            if (item == null) {
+                continue;
+            }
+
+            totalLength += item.length;
+        }
+
+        // Optimization for entirely empty arrays.
+        if (totalLength == 0) {
+            return createEmptyArray(kind);
+        }
+
+        final T[] all = (T[]) Array.newInstance(kind, totalLength);
+        int pos = 0;
+        for (T[] item : arrays) {
+            if (item == null || item.length == 0) {
+                continue;
+            }
+            System.arraycopy(item, 0, all, pos, item.length);
+            pos += item.length;
+        }
+        return all;
     }
 
+    private static @NonNull <T> T[] createEmptyArray(Class<T> kind) {
+        if (kind == String.class) {
+            return (T[]) EmptyArray.STRING;
+        } else if (kind == Object.class) {
+            return (T[]) EmptyArray.OBJECT;
+        }
+
+        return (T[]) Array.newInstance(kind, 0);
+    }
+
+
     /**
      * Adds value to given array if not already present, providing set-like
      * behavior.
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index dfd6f95..cc468f4 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -33,7 +33,13 @@
 
 import com.android.internal.os.IResultReceiver;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 public class BaseIWindow extends IWindow.Stub {
+
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
+    public BaseIWindow() {}
+
     private IWindowSession mSession;
     public int mSeq;
 
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index dc45f78..32867a8 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -558,7 +558,7 @@
 
     /**
      * Returns the password history hash factor, needed to check new password against password
-     * history with {@link #checkPasswordHistory(String, byte[], int)}
+     * history with {@link #checkPasswordHistory(byte[], byte[], int)}
      */
     public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
         try {
@@ -1242,23 +1242,6 @@
         return res;
     }
 
-    /**
-     * Transform a pattern byte array to base zero form.
-     * @param bytes pattern byte array.
-     * @return The pattern in base zero form.
-     */
-    public static byte[] patternByteArrayToBaseZero(byte[] bytes) {
-        if (bytes == null) {
-            return new byte[0];
-        }
-        final int patternSize = bytes.length;
-        byte[] res = new byte[patternSize];
-        for (int i = 0; i < patternSize; i++) {
-            res[i] = (byte) (bytes[i] - '1');
-        }
-        return res;
-    }
-
     /*
      * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
      * at least a second level of protection. First level is that the file
diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/core/java/com/android/server/job/JobSchedulerInternal.java
similarity index 77%
rename from services/core/java/com/android/server/job/JobSchedulerInternal.java
rename to core/java/com/android/server/job/JobSchedulerInternal.java
index 425ec47..dbf3b98 100644
--- a/services/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -16,7 +16,6 @@
 
 package com.android.server.job;
 
-import android.annotation.UserIdInt;
 import android.app.job.JobInfo;
 
 import java.util.List;
@@ -27,31 +26,6 @@
  */
 public interface JobSchedulerInternal {
 
-    // Bookkeeping about app standby bucket scheduling
-
-    /**
-     * The current bucket heartbeat ordinal
-     */
-    long currentHeartbeat();
-
-    /**
-     * Heartbeat ordinal at which the given standby bucket's jobs next become runnable
-     */
-    long nextHeartbeatForBucket(int bucket);
-
-    /**
-     * Heartbeat ordinal for the given app.  This is typically the heartbeat at which
-     * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run
-     * jobs in a long time is immediately runnable even if the app is bucketed into
-     * an infrequent time allocation.
-     */
-    public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, int appBucket);
-
-    /**
-     * Tell the scheduler when a JobServiceContext starts running a job in an app
-     */
-    void noteJobStart(String packageName, int userId);
-
     /**
      * Returns a list of pending jobs scheduled by the system service.
      */
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index d42c43b..844a898 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -33,46 +33,10 @@
 
     srcs: [
         "android_animation_PropertyValuesHolder.cpp",
-        "android_graphics_Canvas.cpp",
-        "android_graphics_ColorSpace.cpp",
-        "android_graphics_drawable_AnimatedVectorDrawable.cpp",
-        "android_graphics_drawable_VectorDrawable.cpp",
-        "android_graphics_Picture.cpp",
-        "android_nio_utils.cpp",
         "android_os_SystemClock.cpp",
         "android_os_SystemProperties.cpp",
         "android_util_EventLog.cpp",
         "android_util_Log.cpp",
-        "android_util_PathParser.cpp",
-        "android_view_DisplayListCanvas.cpp",
-        "android_view_RenderNode.cpp",
-        "android/graphics/Bitmap.cpp",
-        "android/graphics/BitmapFactory.cpp",
-        "android/graphics/ByteBufferStreamAdaptor.cpp",
-        "android/graphics/ColorFilter.cpp",
-        "android/graphics/CreateJavaOutputStreamAdaptor.cpp",
-        "android/graphics/FontFamily.cpp",
-        "android/graphics/FontUtils.cpp",
-        "android/graphics/Graphics.cpp",
-        "android/graphics/ImageDecoder.cpp",
-        "android/graphics/MaskFilter.cpp",
-        "android/graphics/Matrix.cpp",
-        "android/graphics/NinePatch.cpp",
-        "android/graphics/NinePatchPeeker.cpp",
-        "android/graphics/Paint.cpp",
-        "android/graphics/PaintFilter.cpp",
-        "android/graphics/Path.cpp",
-        "android/graphics/PathEffect.cpp",
-        "android/graphics/PathMeasure.cpp",
-        "android/graphics/Picture.cpp",
-        "android/graphics/Region.cpp",
-        "android/graphics/Shader.cpp",
-        "android/graphics/Typeface.cpp",
-        "android/graphics/Utils.cpp",
-        "android/graphics/fonts/Font.cpp",
-        "android/graphics/fonts/FontFamily.cpp",
-        "android/graphics/text/LineBreaker.cpp",
-        "android/graphics/text/MeasuredText.cpp",
         "com_android_internal_util_VirtualRefBasePtr.cpp",
         "com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp",
     ],
@@ -83,21 +47,23 @@
         "bionic/libc/private",
 
         "external/skia/include/private",
-        "external/skia/src/codec",
-        "external/skia/src/core",
-        "external/skia/src/effects",
-        "external/skia/src/image",
-        "external/skia/src/images",
         "frameworks/base/media/jni",
         "system/media/camera/include",
         "system/media/private/camera/include",
     ],
 
+    static_libs: [
+        "libandroid_graphics",
+    ],
+
+    whole_static_libs: ["libandroid_graphics"],
+
     shared_libs: [
         "libbase",
         "libcutils",
         "libharfbuzz_ng",
         "libhwui",
+        "libjpeg",
         "liblog",
         "libminikin",
         "libnativehelper",
@@ -105,7 +71,6 @@
         "libziparchive",
     ],
 
-    local_include_dirs: ["android/graphics"],
     export_include_dirs: [
         ".",
         "include",
@@ -141,7 +106,6 @@
                 "android_database_SQLiteDebug.cpp",
                 "android_view_CompositionSamplingListener.cpp",
                 "android_view_DisplayEventReceiver.cpp",
-                "android_view_TextureLayer.cpp",
                 "android_view_InputChannel.cpp",
                 "android_view_InputDevice.cpp",
                 "android_view_InputEventReceiver.cpp",
@@ -157,7 +121,6 @@
                 "android_view_SurfaceControl.cpp",
                 "android_view_SurfaceSession.cpp",
                 "android_view_TextureView.cpp",
-                "android_view_ThreadedRenderer.cpp",
                 "android_view_VelocityTracker.cpp",
                 "android_text_AndroidCharacter.cpp",
                 "android_text_Hyphenator.cpp",
@@ -188,21 +151,6 @@
                 "android_util_StringBlock.cpp",
                 "android_util_XmlBlock.cpp",
                 "android_util_jar_StrictJarFile.cpp",
-                "android/graphics/AnimatedImageDrawable.cpp",
-                "android/graphics/Camera.cpp",
-                "android/graphics/CanvasProperty.cpp",
-                "android/graphics/GIFMovie.cpp",
-                "android/graphics/GraphicBuffer.cpp",
-                "android/graphics/Interpolator.cpp",
-                "android/graphics/Movie.cpp",
-                "android/graphics/MovieImpl.cpp",
-                "android/graphics/BitmapRegionDecoder.cpp",
-                "android/graphics/SurfaceTexture.cpp",
-                "android/graphics/YuvToJpegEncoder.cpp",
-                "android/graphics/pdf/PdfDocument.cpp",
-                "android/graphics/pdf/PdfEditor.cpp",
-                "android/graphics/pdf/PdfRenderer.cpp",
-                "android/graphics/pdf/PdfUtils.cpp",
                 "android_media_AudioEffectDescriptor.cpp",
                 "android_media_AudioRecord.cpp",
                 "android_media_AudioSystem.cpp",
@@ -302,7 +250,6 @@
                 "libmeminfo",
                 "libaudioclient",
                 "libaudiopolicy",
-                "libjpeg",
                 "libusbhost",
                 "libpdfium",
                 "libimg_utils",
@@ -328,9 +275,6 @@
 
                 // our headers include libnativewindow's public headers
                 "libnativewindow",
-
-                // GraphicsJNI.h includes hwui headers
-                "libhwui",
             ],
             generated_sources: ["android_util_StatsLogInternal.cpp"],
         },
@@ -344,6 +288,8 @@
             ],
             include_dirs: [
                 "external/vulkan-headers/include",
+                "frameworks/native/libs/nativebase/include",
+                "frameworks/native/libs/nativewindow/include"
             ],
             shared_libs: [
                 "libicui18n",
@@ -353,6 +299,7 @@
                 "libandroidfw",
                 "libcompiler_rt",
                 "libutils",
+                "libhostgraphics",
             ],
         },
         linux_glibc: {
@@ -367,3 +314,140 @@
         },
     },
 }
+
+cc_library_static {
+    name: "libandroid_graphics",
+    host_supported: true,
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-non-virtual-dtor",
+        "-Wno-maybe-uninitialized",
+        "-Wno-parentheses",
+
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+
+        "-DU_USING_ICU_NAMESPACE=0",
+
+        "-Wall",
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+    cppflags: ["-Wno-conversion-null"],
+
+    srcs: [
+        "android_graphics_Canvas.cpp",
+        "android_graphics_ColorSpace.cpp",
+        "android_graphics_drawable_AnimatedVectorDrawable.cpp",
+        "android_graphics_drawable_VectorDrawable.cpp",
+        "android_graphics_Picture.cpp",
+        "android_nio_utils.cpp",
+        "android_view_DisplayListCanvas.cpp",
+        "android_view_RenderNode.cpp",
+        "android_util_PathParser.cpp",
+
+        "android/graphics/AnimatedImageDrawable.cpp",
+        "android/graphics/Bitmap.cpp",
+        "android/graphics/BitmapFactory.cpp",
+        "android/graphics/ByteBufferStreamAdaptor.cpp",
+        "android/graphics/Camera.cpp",
+        "android/graphics/CanvasProperty.cpp",
+        "android/graphics/ColorFilter.cpp",
+        "android/graphics/CreateJavaOutputStreamAdaptor.cpp",
+        "android/graphics/FontFamily.cpp",
+        "android/graphics/FontUtils.cpp",
+        "android/graphics/Graphics.cpp",
+        "android/graphics/ImageDecoder.cpp",
+        "android/graphics/Interpolator.cpp",
+        "android/graphics/MaskFilter.cpp",
+        "android/graphics/Matrix.cpp",
+        "android/graphics/NinePatch.cpp",
+        "android/graphics/NinePatchPeeker.cpp",
+        "android/graphics/Paint.cpp",
+        "android/graphics/PaintFilter.cpp",
+        "android/graphics/Path.cpp",
+        "android/graphics/PathEffect.cpp",
+        "android/graphics/PathMeasure.cpp",
+        "android/graphics/Picture.cpp",
+        "android/graphics/Region.cpp",
+        "android/graphics/Shader.cpp",
+        "android/graphics/Typeface.cpp",
+        "android/graphics/Utils.cpp",
+        "android/graphics/YuvToJpegEncoder.cpp",
+        "android/graphics/fonts/Font.cpp",
+        "android/graphics/fonts/FontFamily.cpp",
+        "android/graphics/text/LineBreaker.cpp",
+        "android/graphics/text/MeasuredText.cpp",
+    ],
+
+    local_include_dirs: [
+        "include",  // NEEDED FOR ANDROID RUNTIME
+        "android/graphics",
+    ],
+
+    export_include_dirs: [
+        ".",
+    ],
+
+    include_dirs: [
+        "external/skia/include/private",
+        "external/skia/src/codec",
+        "external/skia/src/core",
+        "external/skia/src/effects",
+        "external/skia/src/image",
+        "external/skia/src/images",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libharfbuzz_ng",
+        "libhwui",
+        "liblog",
+        "libminikin",
+        "libnativehelper",
+        "libz",
+        "libziparchive",
+        "libjpeg",
+    ],
+
+    target: {
+        android: {
+            srcs: [ // sources that depend on android only libraries
+                "android_view_TextureLayer.cpp",
+                "android_view_ThreadedRenderer.cpp",
+                "android/graphics/BitmapRegionDecoder.cpp",
+                "android/graphics/GIFMovie.cpp",
+                "android/graphics/GraphicBuffer.cpp",
+                "android/graphics/Movie.cpp",
+                "android/graphics/MovieImpl.cpp",
+                "android/graphics/SurfaceTexture.cpp",
+                "android/graphics/pdf/PdfDocument.cpp",
+                "android/graphics/pdf/PdfEditor.cpp",
+                "android/graphics/pdf/PdfRenderer.cpp",
+                "android/graphics/pdf/PdfUtils.cpp",
+            ],
+            shared_libs: [
+                "libandroidfw",
+                "libnativewindow",
+                "libgui",
+                "libpdfium",
+            ],
+            static_libs: [
+                "libgif",
+            ],
+        },
+        host: {
+            cflags: [
+                "-Wno-unused-const-variable",
+                "-Wno-unused-function",
+            ],
+            static_libs: [
+                "libandroidfw",
+            ],
+        }
+    },
+}
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index 00e5ba3..706a2b8 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -20,7 +20,6 @@
 #include <nativehelper/JNIHelp.h>
 
 #include "android_os_Parcel.h"
-#include "android/graphics/GraphicsJNI.h"
 #include "android/graphics/GraphicBuffer.h"
 
 #include <android/hardware_buffer.h>
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 8ddbe72..c75c54b 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -27,7 +27,6 @@
 #include "android_os_Parcel.h"
 #include "android_view_MotionEvent.h"
 #include "android_util_Binder.h"
-#include "android/graphics/Matrix.h"
 
 #include "core_jni_helpers.h"
 
@@ -701,6 +700,21 @@
     return event->getYPrecision();
 }
 
+static jfloat android_view_MotionEvent_nativeGetXCursorPosition(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getXCursorPosition();
+}
+
+static jfloat android_view_MotionEvent_nativeGetYCursorPosition(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getYCursorPosition();
+}
+
+static void android_view_MotionEvent_nativeSetCursorPosition(jlong nativePtr, jfloat x, jfloat y) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->setCursorPosition(x, y);
+}
+
 static jlong android_view_MotionEvent_nativeGetDownTimeNanos(jlong nativePtr) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
     return event->getDownTime();
@@ -871,6 +885,15 @@
     { "nativeGetYPrecision",
             "(J)F",
             (void*)android_view_MotionEvent_nativeGetYPrecision },
+    { "nativeGetXCursorPosition",
+            "(J)F",
+            (void*)android_view_MotionEvent_nativeGetXCursorPosition },
+    { "nativeGetYCursorPosition",
+            "(J)F",
+            (void*)android_view_MotionEvent_nativeGetYCursorPosition },
+    { "nativeSetCursorPosition",
+            "(JFF)V",
+            (void*)android_view_MotionEvent_nativeSetCursorPosition },
     { "nativeGetDownTimeNanos",
             "(J)J",
             (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 0d95f99..8eb9c9a 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -57,8 +57,8 @@
 
 namespace android {
 
-static const char* const OutOfResourcesException =
-    "android/view/Surface$OutOfResourcesException";
+static const char* const IllegalArgumentException = "java/lang/IllegalArgumentException";
+static const char* const OutOfResourcesException = "android/view/Surface$OutOfResourcesException";
 
 static struct {
     jclass clazz;
@@ -155,7 +155,7 @@
         jobject surfaceTextureObj) {
     sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj));
     if (producer == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException",
+        jniThrowException(env, IllegalArgumentException,
                 "SurfaceTexture has already been released");
         return 0;
     }
@@ -183,7 +183,7 @@
 static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jlong nativeObject) {
     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
     if (!isSurfaceValid(sur)) {
-        doThrowIAE(env);
+        jniThrowException(env, IllegalArgumentException, NULL);
         return JNI_FALSE;
     }
     int value = 0;
@@ -212,7 +212,7 @@
     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
 
     if (!isSurfaceValid(surface)) {
-        doThrowIAE(env);
+        jniThrowException(env, IllegalArgumentException, NULL);
         return 0;
     }
 
@@ -293,7 +293,7 @@
     // unlock surface
     status_t err = surface->unlockAndPost();
     if (err < 0) {
-        doThrowIAE(env);
+        jniThrowException(env, IllegalArgumentException, NULL);
     }
 }
 
@@ -344,7 +344,7 @@
         jlong nativeObject, jobject parcelObj) {
     Parcel* parcel = parcelForJavaObject(env, parcelObj);
     if (parcel == NULL) {
-        doThrowNPE(env);
+        jniThrowNullPointerException(env, NULL);
         return 0;
     }
 
@@ -385,7 +385,7 @@
         jlong nativeObject, jobject parcelObj) {
     Parcel* parcel = parcelForJavaObject(env, parcelObj);
     if (parcel == NULL) {
-        doThrowNPE(env);
+        jniThrowNullPointerException(env, NULL);
         return;
     }
     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a579229..5cbf81c 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -20,7 +20,6 @@
 #include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 #include "android_hardware_input_InputWindowHandle.h"
-#include "android/graphics/Bitmap.h"
 #include "android/graphics/Region.h"
 #include "core_jni_helpers.h"
 
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 71e3860..6ab0fc9 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -15,3 +15,6 @@
 
 # Launcher
 hyunyoungs@google.com
+
+# Graphics stats
+jreck@google.com
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index c534aa4..5d4be55 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -38,10 +38,10 @@
 
     optional ConstantsProto settings = 1;
 
-    optional int32 current_heartbeat = 14;
-    repeated int32 next_heartbeat = 15;
-    optional int64 last_heartbeat_time_millis = 16;
-    optional int64 next_heartbeat_time_millis = 17;
+    reserved 14; // current_heartbeat
+    reserved 15; // next_heartbeat
+    reserved 16; // last_heartbeat_time_millis
+    reserved 17; // next_heartbeat_time_millis
     optional bool in_parole = 18;
     optional bool in_thermal = 19;
 
@@ -64,7 +64,7 @@
         optional bool is_uid_backing_up = 7;
         optional bool is_component_present = 8;
 
-        optional int64 last_run_heartbeat = 9;
+        reserved 9; // last_run_heartbeat
     }
     repeated RegisteredJob registered_jobs = 3;
 
@@ -214,13 +214,13 @@
     // assignment. This should be prime relative to common time interval lengths
     // such as a quarter-hour or day, so that the heartbeat drifts relative to
     // wall-clock milestones.
-    optional int64 standby_heartbeat_time_ms = 19;
+    reserved 19; // standby_heartbeat_time_ms
     // Mapping: standby bucket -> number of heartbeats between each sweep of
     // that bucket's jobs.
     // Bucket assignments as recorded in the JobStatus objects are normalized to
     // be indices into this array, rather than the raw constants used by
     // AppIdleHistory.
-    repeated int32 standby_beats = 20;
+    reserved 20; // standby_beats
     // The fraction of a job's running window that must pass before we
     // consider running it when the network is congested.
     optional double conn_congestion_delay_frac = 21;
@@ -229,7 +229,7 @@
     optional double conn_prefetch_relax_frac = 22;
     // Whether to use heartbeats or rolling window for quota management. True
     // will use heartbeats, false will use a rolling window.
-    optional bool use_heartbeats = 23;
+    reserved 23; // use_heartbeats
 
     message QuotaController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/stats/textclassifier/textclassifier_enums.proto b/core/proto/android/stats/textclassifier/textclassifier_enums.proto
new file mode 100644
index 0000000..1885f19
--- /dev/null
+++ b/core/proto/android/stats/textclassifier/textclassifier_enums.proto
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.stats.textclassifier;
+option java_multiple_files = true;
+
+enum EventType {
+    TYPE_UNKNOWN = 0;
+    // User started a new selection.
+    SELECTION_STARTED = 1;
+    // User modified an existing selection.
+    SELECTION_MODIFIED = 2;
+    // Smart selection triggered for a single token (word).
+    SMART_SELECTION_SINGLE = 3;
+    // Smart selection triggered spanning multiple tokens (words).
+    SMART_SELECTION_MULTI = 4;
+    // Something else other than user or the default TextClassifier triggered a selection.
+    AUTO_SELECTION = 5;
+    // Smart actions shown to the user.
+    ACTIONS_SHOWN = 6;
+    // User clicked a link.
+    LINK_CLICKED = 7;
+    // User typed over the selection.
+    OVERTYPE = 8;
+    // User clicked on Copy action.
+    COPY_ACTION = 9;
+    // User clicked on Paste action.
+    PASTE_ACTION = 10;
+    // User clicked on Cut action.
+    CUT_ACTION = 11;
+    // User clicked on Share action.
+    SHARE_ACTION = 12;
+    // User clicked on a Smart action.
+    SMART_ACTION = 13;
+    // User dragged+dropped the selection.
+    SELECTION_DRAG = 14;
+    // Selection is destroyed.
+    SELECTION_DESTROYED = 15;
+    // User clicked on a custom action.
+    OTHER_ACTION = 16;
+    // User clicked on Select All action
+    SELECT_ALL = 17;
+    // User reset the smart selection.
+    SELECTION_RESET = 18;
+    // User composed a reply.
+    MANUAL_REPLY = 19;
+    // TextClassifier generated some actions
+    ACTIONS_GENERATED = 20;
+}
+
+enum WidgetType {
+    WIDGET_TYPE_UNKNOWN = 0;
+    // Standard TextView
+    WIDGET_TYPE_TEXTVIEW = 1;
+    // EditText
+    WIDGET_TYPE_EDITTEXT = 2;
+    // Not selectable textview
+    WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = 3;
+    // Standard Webview
+    WIDGET_TYPE_WEBVIEW = 4;
+    // Editable TextView
+    WIDGET_TYPE_EDIT_WEBVIEW = 5;
+    // Custom text widget
+    WIDGET_TYPE_CUSTOM_TEXTVIEW = 6;
+    // Custom editable text widget.
+    WIDGET_TYPE_CUSTOM_EDITTEXT = 7;
+    // Non-selectable text widget.
+    WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = 8;
+    // Notification
+    WIDGET_TYPE_NOTIFICATION = 9;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index aa440d3..6a20484 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4599,6 +4599,11 @@
     <permission android:name="android.permission.MONITOR_INPUT"
                 android:protectionLevel="signature" />
 
+    <!-- Allows query of any normal app on the device, regardless of manifest declarations. -->
+    <permission android:name="android.permission.QUERY_ALL_PACKAGES"
+                android:protectionLevel="normal" />
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 7a0d475..878cda1 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Stemboodskappe"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-oproepe"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Hoëprioriteit-SIM-status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Ander party het TTY-modus VOL versoek"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Ander party het TTY-modus GOD versoek"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Ander party het TTY-modus SOD versoek"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 11ab44d..f5ef6ca 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"የድምጽ መልዕክቶች"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"የWi-Fi ጥሪ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"የሲም ሁኔታ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ከፍተኛ ቅድሚያ ተሰጪ የሲም ኹናቴ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ FULL ጠይቋል"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ HCO ጠይቋል"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ VCO ጠይቋል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6edc933..217c3cf 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -99,6 +99,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"رسائل البريد الصوتي"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏الاتصال عبر Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‏حالة شريحة SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‏حالة شريحة SIM ذات أولوية"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏طلب النظير وضع TTY الكامل"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏طلب النظير وضع TTY على HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏طلب النظير وضع TTY على VCO"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 3660403..6ea6a52 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভইচমেইলৰ বাৰ্তাসমূহ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ৱাই-ফাই কলিং"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ছিমৰ স্থিতি"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"উচ্চ অগ্ৰাধিকাৰযুক্ত ছিমৰ স্থিতি"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড FULLলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড HCOলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড VCO লৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index e2b3998..47572bc87 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Səsli e-poçt mesajları"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi zəngi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Yüksək Prioritetli SIM statusu"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Eskpert TTY Rejimi FULL-u sorğuladı"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Ekspert TTY Rejimi HCO-nu sorğuladı"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Ekspert TTY Rejimi VCO-nu sorğuladı"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 821b730..9bd9e93 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Pozivanje preko Wi-Fi mreže"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Obaveštenja SIM kartice sa statusom „visok prioritet“"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Korisnik zahteva POTPUN režim TTY"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Korisnik zahteva PRENOS ZVUKA za režim TTY"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Korisnik zahteva PRENOS GLASA za režim TTY"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index d573202..2b5d8c9 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Паведамленні галасавой пошты"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-тэлефанія"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карты"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Стан SIM-карты з высокім прыярытэтам"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Аднарангавая прылада запытала рэжым TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Аднарангавая прылада запытала рэжым TTY НСО"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Аднарангавая прылада запытала рэжым TTY VCO"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e073b7d..c9220a0 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Съобщения в гласовата поща"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Обаждания през Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Състояние на SIM картата"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Състояние на SIM картата с висок приоритет"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Отсрещният потребител заяви пълен TTY режим (FULL)"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Отсрещният потребител заяви TTY режим с пренос на слух (HCO)"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Отсрещният потребител заяви TTY режим с пренос на глас (VCО)"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 368ff90..b6a9240 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভয়েসমেল মেসেজ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ওয়াই-ফাই কলিং"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"সিম কার্ডের স্টাটাস"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"উচ্চ প্রায়রিটি সিম স্ট্যাটাস"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"পির TTY মোড FULL অনুরোধ করেছে"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"পির TTY মোড HCO অনুরোধ করেছে"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"পির TTY মোড VCO অনুরোধ করেছে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index ce852b6..02d65e3 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Pozivanje putem WiFi-ja"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status visokog prioriteta SIM-a"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Ravnopravni uređaj zatražio načina rada TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Ravnopravni uređaj zatražio načina rada TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Ravnopravni uređaj zatražio načina rada TTY VCO"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index bbf1736..0ec04b6 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Missatges de veu"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Trucades per Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estat de la SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estat de la SIM d\'alta prioritat"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"L\'altre dispositiu ha sol·licitat el mode TTY COMPLET."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"L\'altre dispositiu ha sol·licitat el mode TTY HCO."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"L\'altre dispositiu ha sol·licitat el mode TTY VCO."</string>
@@ -573,9 +574,9 @@
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Torna a registrar la teva cara."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ja no es reconeix la teva cara. Torna-ho a provar."</string>
     <string name="face_acquired_too_similar" msgid="1508776858407646460">"És massa semblant; canvia de postura."</string>
-    <string name="face_acquired_pan_too_extreme" msgid="4581629343077288178">"Inclina el cap una mica menys."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="4019954263012496468">"Inclina el cap una mica menys."</string>
-    <string name="face_acquired_roll_too_extreme" msgid="6312973147689664409">"No inclinis tant el cap."</string>
+    <string name="face_acquired_pan_too_extreme" msgid="4581629343077288178">"No giris tant el cap."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="4019954263012496468">"No inclinis tant el cap."</string>
+    <string name="face_acquired_roll_too_extreme" msgid="6312973147689664409">"No giris tant el cap."</string>
     <string name="face_acquired_obscured" msgid="5357207702967893283">"Suprimeix qualsevol cosa que amagui la teva cara."</string>
     <string name="face_acquired_sensor_dirty" msgid="7905138627046865579">"Neteja la part superior de la pantalla, inclosa la barra negra"</string>
   <string-array name="face_acquired_vendor">
@@ -1483,7 +1484,7 @@
     <string name="back_button_label" msgid="2300470004503343439">"Enrere"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Següent"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Omet"</string>
-    <string name="no_matches" msgid="8129421908915840737">"Cap coincidència"</string>
+    <string name="no_matches" msgid="8129421908915840737">"No s\'ha trobat cap coincidència"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Troba-ho a la pàgina"</string>
     <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
       <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 4171a8b..3a77e9c 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Hlasové zprávy"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Volání přes Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stav SIM karty"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stav SIM karty: vysoká priorita"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner požádal o přechod na režim TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner požádal o přechod na režim TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner požádal o přechod na režim TTY VCO"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b6cb874..c10680e 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talebeskeder"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-opkald"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-kort med høj prioritet"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Den anden enhed har skiftet til FULD TTY-tilstand"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Den anden enhed har skiftet til TTY-tilstanden HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Den anden enhed har skiftet til TTY-tilstanden VCO"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 114d801..933741a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mailboxnachrichten"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"WLAN-Telefonie"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status der SIM-Karte"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Benachrichtigungen mit hoher Priorität von der SIM-Karte"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer hat TTY-Modus \"Vollständig\" angefordert."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer hat TTY-Modus \"HCO\" angefordert."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer hat TTY-Modus \"VC\" angefordert."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 44357ff..e5ff8a8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Μηνύματα αυτόματου τηλεφωνητή"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Κλήση Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Κατάσταση SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Κατάσταση SIM υψηλής προτεραιότητας"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Αίτημα peer για TTY ΠΛΗΡΗΣ Λειτουργία"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Αίτημα peer για TTY Λειτουργία HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Αίτημα peer για TTY Λειτουργία VCO"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index cc389f3..4f0ebc5 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 0e6d49c..d1ac6dc 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index cc389f3..4f0ebc5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index cc389f3..4f0ebc5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index dade85e..66aa946 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎Voicemail messages‎‏‎‎‏‎"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎Wi-Fi calling‎‏‎‎‏‎"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎SIM status‎‏‎‎‏‎"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎High priority SIM status‎‏‎‎‏‎"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎Peer requested TTY Mode FULL‎‏‎‎‏‎"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎Peer requested TTY Mode HCO‎‏‎‎‏‎"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎Peer requested TTY Mode VCO‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 3a2ea3e..68604d9 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensajes del buzón de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Llamada con Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estado de SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notificaciones de prioridad alta sobre el estado de la SIM"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"El dispositivo del mismo nivel solicitó el modo TTY FULL."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"El dispositivo del mismo nivel solicitó el modo TTY HCO."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"El dispositivo del mismo nivel solicitó el modo TTY VCO."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 633759b..f290fae 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensajes de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Llamada por Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estado de la tarjeta SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado de SIM de alta prioridad"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Un dispositivo ha solicitado el modo TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Un dispositivo ha solicitado el modo TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Un dispositivo ha solicitado el modo TTY VCO"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 86843c7..8e07555 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Kõnepostisõnumid"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"WiFi-kõned"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kaardi olek"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Kõrge prioriteediga SIM-i olek"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner taotles TTY-režiimi TÄIELIK"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner taotles TTY-režiimi HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner taotles TTY-režiimi VCO"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d25fe8c..7303406 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Erantzungailuko mezuak"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi bidezko deiak"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIMaren egoera"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM txartelaren lehentasun handiko jakinarazpenak"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Beste gailuak TTY osagarria FULL moduan erabiltzea eskatu du"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Beste gailuak TTY osagarria HCO moduan erabiltzea eskatu du"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Beste gailuak TTY osagarria VCO moduan erabiltzea eskatu du"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 48cdafc..44428dc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"پیام‌های پست صوتی"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏تماس ازطریق Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"وضعیت سیم‌کارت"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"وضعیت سیم با اولویت بالا"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏دستگاه مرتبط درخواست TTY حالت FULL کرد"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏دستگاه مرتبط درخواست TTY حالت HCO کرد"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏دستگاه مرتبط درخواست TTY حالت VCO کرد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index cd9a711..ccc9d33 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Vastaajaviestit"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-puhelut"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kortin tila"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Tärkeät SIM-ilmoitukset"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Toinen käyttäjä vaihtoi TTY-tilaksi TÄYSI"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Toinen käyttäjä vaihtoi TTY-tilaksi HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Toinen käyttäjä vaihtoi TTY-tilaksi VCO"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2bfef39..99f874d 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messages vocaux"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Appels Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"État de la carte SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"État SIM de priorité élevée"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Mode TTY COMPLET demandé par un pair"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Mode TTY HCO demandé par un pair"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Mode TTY VCO demandé par un pair"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 041668f..bac6066 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messages vocaux"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Appels Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"État de la carte SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notifications prioritaires de la carte SIM"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Mode TTY demandé par l\'interlocuteur : COMPLET"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Mode TTY demandé par l\'interlocuteur : HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Mode TTY demandé par l\'interlocuteur : VCO"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index b3eed4a..40c1ed2 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensaxes de correo de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por wifi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estado da SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado da SIM con prioridade alta"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Outro dispositivo solicitou o modo TTY COMPLETO"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Outro dispositivo solicitou o modo TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Outro dispositivo solicitou o modo TTY VCO"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1b96172..bbb344b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"વૉઇસમેઇલ સંદેશા"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"વાઇ-ફાઇ કૉલિંગ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"સિમનું સ્ટેટસ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"સિમ કાર્ડનું ઉચ્ચ પ્રાધાન્યતાનું સ્ટેટસ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"પીઅરે TTY મોડ પૂર્ણની વિનંતી કરી"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"પીઅરે TTY મોડ HCO ની વિનંતી કરી"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"પીઅરે TTY મોડ VCO ની વિનંતી કરી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 9f0df13..f130e01 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"वॉइसमेल संदेश"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"वाई-फ़ाई कॉलिंग"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"सिम की स्थिति"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"सिम की ज़रूरी सूचनाओं की स्थिति"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"पीयर ने टेलीटाइपराइटर (TTY) मोड फ़ुल का अनुरोध किया"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"पीयर ने टेलीटाइपराइटर (TTY) मोड एचसीओ (HCO) का अनुरोध किया"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"पीयर ने टेलीटाइपराइटर (TTY) मोड वीसीओ (VCO) का अनुरोध किया"</string>
@@ -282,9 +283,9 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने संपर्क देखने की अनुमति देना चाहते हैं?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"जगह"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"इस डिवाइस की जगह तक पहुंचने दें"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को इस डिवाइस की \'जगह की जानकारी\' एक्सेस करने की अनुमति देना चाहते हैं?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को इस डिवाइस की \'जगह की जानकारी\' ऐक्सेस करने की अनुमति देना चाहते हैं?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"ऐप्लिकेशन, डिवाइस की जगह की जानकारी सिर्फ़ तभी देख पाएगा जब आप इसका इस्तेमाल कर रहे हों"</string>
-    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"क्या आप <xliff:g id="APP_NAME">%1$s</xliff:g> को हमेशा के लिए जगह की जानकारी एक्सेस करने की अनुमति देना चाहते हैं?"</string>
+    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"क्या आप <xliff:g id="APP_NAME">%1$s</xliff:g> को हमेशा के लिए जगह की जानकारी ऐक्सेस करने की अनुमति देना चाहते हैं?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"इस समय ऐप्लिकेशन, डिवाइस की \'जगह की जानकारी\' सिर्फ़ तभी देख पाएगा जब आप इसका इस्तेमाल कर रहे हों"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"कैलेंडर"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"अपने कैलेंडर को ऐक्सेस करने"</string>
@@ -294,7 +295,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को एसएमएस (मैसेज) भेजने और देखने की अनुमति देना चाहते हैं?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"मेमोरी"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"अपने डिवाइस पर मौजूद फ़ोटो, मीडिया और फ़ाइलें ऐक्सेस करने की"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को डिवाइस पर मौजूद फ़ोटो, ऑडियो-वीडियो और फ़ाइलें एक्सेस करने की अनुमति दें?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को डिवाइस पर मौजूद फ़ोटो, ऑडियो-वीडियो और फ़ाइलें ऐक्सेस करने की अनुमति दें?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"माइक्रोफ़ोन"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ऑडियो रिकॉर्ड करें"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को ऑडियो रिकॉर्ड करने की अनुमति देना चाहते हैं?"</string>
@@ -306,7 +307,7 @@
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को फ़ोटो खींचने और वीडियो रिकॉर्ड करने की अनुमति देना चाहते हैं?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"कॉल लॉग"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"कॉल लॉग की जानकारी देखना और उसमें बदलाव करना"</string>
-    <string name="permgrouprequest_calllog" msgid="8487355309583773267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने काॅल लाॅग एक्सेस करने की मंज़ूरी देना चाहते हैं?"</string>
+    <string name="permgrouprequest_calllog" msgid="8487355309583773267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने काॅल लाॅग ऐक्सेस करने की मंज़ूरी देना चाहते हैं?"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"फ़ोन"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"फ़ोन कॉल करने और उन्हें प्रबंधित करने की अनुमति दें"</string>
     <string name="permgrouprequest_phone" msgid="9166979577750581037">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को फ़ोन कॉल करने और उन्हें प्रबंधित करने की अनुमति दें?"</string>
@@ -340,22 +341,22 @@
     <string name="permlab_answerPhoneCalls" msgid="4077162841226223337">"फ़ोन कॉल का जवाब दें"</string>
     <string name="permdesc_answerPhoneCalls" msgid="2901889867993572266">"ऐप्लिकेशन को किसी इनकमिंग फ़ोन कॉल का जवाब देने देती है."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"मैसेज (एसएमएस) पाएं"</string>
-    <string name="permdesc_receiveSms" msgid="6424387754228766939">"ऐप को मैसेज (एसएमएस) को प्राप्‍त और संसाधित करने देता है. इसका अर्थ है कि ऐप आपके डिवाइस पर भेजे गए संदेशों की निगरानी आपको दिखाए बिना कर सकता है और उन्‍हें हटा सकता है."</string>
+    <string name="permdesc_receiveSms" msgid="6424387754228766939">"एप्लिकेशन को मैसेज (एसएमएस) पाने और प्रोसेस करने देता है. इसका मतलब है कि एप्लिकेशन आपके डिवाइस पर भेजे गए मैसेज की निगरानी आपको दिखाए बिना कर सकता है और उन्‍हें हटा सकता है."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"मैसेज (एमएमएस) पाएं"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"ऐप को मल्टीमीडिया मैसेज (एमएमएस) को पाने और उन पर कार्रवाई करने देता है. इसका मतलब है कि ऐप आपके डिवाइस पर भेजे गए मैसेज की निगरानी आपको दिखाए बिना कर सकता है और उन्‍हें हटा सकता है."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"सेल ब्रॉडकास्ट (CBC) मैसेज पढ़ें"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"ऐप को, वो सेल ब्रॉडकास्ट (CBC) मैसेज पढ़ने देता है जो आपके डिवाइस को मिले हैं. सेल ब्रॉडकास्ट (CBC) अलर्ट कुछ स्थानों (लोकेशन) पर आपको आपातकालीन स्‍थितियों की चेतावनी देने के लिए दिए जाते हैं. आपातकालीन सेल ब्रॉडकास्ट (CBC) मिलने पर, धोखा देने वाले ऐप आपके डिवाइस के परफ़ॉर्मेंस या कार्यवाही में दखल दे सकते हैं."</string>
-    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"सदस्यता-प्राप्त फ़ीड पढ़ें"</string>
-    <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"ऐप्स को वर्तमान में समन्वयित फ़ीड के बारे में विवरण प्राप्त करने देता है."</string>
+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"सदस्यता वाली फ़ीड पढ़ें"</string>
+    <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"एप्‍लिकेशन को मौजूदा समय में सिंक फ़ीड के बारे में जानकारी देता है."</string>
     <string name="permlab_sendSms" msgid="7544599214260982981">"मैसेज (एमएमएस) भेजें और देखें"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"ऐप को मैसेज (एसएमएस) भेजने देता है. इसकी वजह से उम्मीद से ज़्यादा शुल्‍क लग सकते हैं. धोखा देने वाले ऐप आपकी पुष्टि के बिना मैसेज भेजकर आपका पैसा खर्च करवा सकते हैं."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"अपने मैसेज (एसएमएस या एमएमएस) पढ़ें"</string>
     <string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"यह ऐप आपके टैबलेट पर सहेजे गए सभी मैसेज (एसएमएस) पढ़ सकता है."</string>
     <string name="permdesc_readSms" product="tv" msgid="5796670395641116592">"यह ऐप आपके टीवी पर सहेजे गए सभी मैसेज (एसएमएस) पढ़ सकता है."</string>
     <string name="permdesc_readSms" product="default" msgid="6826832415656437652">"यह ऐप आपके फ़ोन पर सहेजे गए सभी मैसेज (एसएमएस) पढ़ सकता है."</string>
-    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"लेख संदेश (WAP) प्राप्त करें"</string>
-    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"ऐप्स  को WAP संदेशों को प्राप्‍त और संसाधित करने देता है. इस अनुमति में आपको भेजे गए संदेशों की निगरानी आपको दिखाए बिना करने और हटाने की क्षमता शामिल है."</string>
-    <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे ऐप्स पुनर्प्राप्त करें"</string>
+    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"टेक्सट मैसेज (WAP) पाएं"</string>
+    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"एप्लिकेशन को WAP मैसेज पाने और प्रोसेस करने देता है. इस अनुमति में आपको भेजे गए मैसेज की निगरानी आपको दिए एप्लिकेशन को दिखाए बिना करने और हटाने की क्षमता शामिल है."</string>
+    <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे ऐप्स फिर से पाएं"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ऐप को माजूदा समय में और हाल ही में चल रही कार्रवाइयों के बारे में जानकारी निकालने देता है. इससे ऐप डिवाइस पर इस्तेमाल किए गए ऐप के बारे में जानकारी खोज सकता है."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"प्रोफ़ाइल और डिवाइस स्‍वामियों को प्रबंधित करें"</string>
     <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"ऐप्‍स को प्रोफ़ाइल स्‍वामी और डिवाइस स्‍वामी सेट करने दें."</string>
@@ -403,7 +404,7 @@
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"ऐप को आने वाला कॉल (इनकमिंग) और किया जाने वाला कॉल (आउटगोइंग) डेटा सहित, आपके टैबलेट के कॉल लॉग को बदलने की अनुमति देता है. धोखा देने वाले ऐप, इसका इस्तेमाल करके आपके कॉल लॉग को मिटा या बदल सकते हैं."</string>
     <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"ऐप को आने वाला कॉल (इनकमिंग) और किया जाने वाला कॉल (आउटगोइंग) डेटा सहित, आपके टीवी के कॉल लॉग को बदलने की अनुमति देता है. धोखा देने वाले ऐप, इसका इस्तेमाल करके आपके कॉल लॉग को मिटा या बदल सकते हैं."</string>
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"ऐप को आने वाला कॉल (इनकमिंग) और किया जाने वाला कॉल (आउटगोइंग) डेटा सहित, आपके फ़ोन के कॉल लॉग को बदलने की अनुमति देता है. धोखा देने वाले ऐप, इसका इस्तेमाल करके आपके कॉल लॉग को मिटा या बदल सकते हैं."</string>
-    <string name="permlab_bodySensors" msgid="4683341291818520277">"शरीर के लिए बने सेंसर (जैसे हृदय गति मॉनीटर) को एक्सेस करें"</string>
+    <string name="permlab_bodySensors" msgid="4683341291818520277">"शरीर के लिए बने सेंसर (जैसे हृदय गति मॉनीटर) को ऐक्सेस करें"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"ऐप को आपकी शारीरिक स्‍थिति, जैसे आपकी हृदय गति पर नज़र रखने वाले सेंसर के डेटा तक पहुंचने देती है."</string>
     <string name="permlab_readCalendar" msgid="6716116972752441641">"कैलेंडर इवेंट और विवरण पढ़ें"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"यह ऐप्लिकेशन आपके टैबलेट पर संग्रहित सभी कैलेंडर इवेंट पढ़ सकता है और आपका कैलेंडर डेटा शेयर कर सकता है या सहेज सकता है."</string>
@@ -415,14 +416,14 @@
     <string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"यह ऐप्लिकेशन आपके फ़ोन पर मौजूद कैलेंडर इवेंट जोड़, निकाल या बदल सकता है. यह ऐप्लिकेशन ऐसे संदेश भेज सकता है जो कैलेंडर स्वामियों से आए हुए लग सकते हैं या यह स्वामियों को सूचित किए बिना इवेंट में बदलाव कर सकता है."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"कुछ और जगह बताने वाले आदेशों तक पहुंच"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ऐप को कुछ और जगह की जानकारी देने वाले आदेशों की पहुंच पाने देता है. इससे ऐप जीपीएस या जगह की जानकारी देने वाले दूसरे स्रोतों के काम में रोक-टोक कर सकता है."</string>
-    <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ऐप्लिकेशन \'जगह की सटीक जानकारी\' सिर्फ़ सामने खुली होने पर एक्सेस करे"</string>
+    <string name="permlab_accessFineLocation" msgid="6265109654698562427">"ऐप्लिकेशन \'जगह की सटीक जानकारी\' सिर्फ़ सामने खुली होने पर ऐक्सेस करे"</string>
     <string name="permdesc_accessFineLocation" msgid="3520508381065331098">"यह ऐप्लिकेशन सिर्फ़ तब आपकी \'जगह की सटीक जानकारी\' का इस्तेमाल कर सकता है जब यह स्क्रीन पर दिखाई दे रहा हो. यह ज़रूरी है कि \'जगह की जानकारी\' वाली ये सेवाएं आपके फ़ोन में मौजूद हों और चालू की गई हों ताकि ऐप्लिकेशन उनका इस्तेमाल कर पाए. ऐसा करने से ज़्यादा बैटरी खर्च हो सकती है."</string>
-    <string name="permlab_accessCoarseLocation" msgid="3707180371693213469">"स्क्रीन पर दिखाई देते समय \'जगह की अनुमानित जानकारी\' (नेटवर्क-आधारित) एक्सेस करें"</string>
+    <string name="permlab_accessCoarseLocation" msgid="3707180371693213469">"स्क्रीन पर दिखाई देते समय \'जगह की अनुमानित जानकारी\' (नेटवर्क-आधारित) ऐक्सेस करें"</string>
     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="8594719010575779120">"यह ऐप्लिकेशन सेल टावर और वाई-फ़ाई नेटवर्क जैसे नेटवर्क स्रोतों के आधार पर आपकी जगह का पता लगा सकता है, लेकिन सिर्फ़ तब, जब ऐप्लिकेशन स्क्रीन पर दिखाई दे रहा हो. यह ज़रूरी है कि \'जगह की जानकारी\' वाली ये सेवाएं आपके टैबलेट में मौजूद हों और चालू की गई हों ताकि ऐप्लिकेशन उनका इस्तेमाल कर पाए."</string>
     <string name="permdesc_accessCoarseLocation" product="tv" msgid="3027871910200890806">"यह ऐप्लिकेशन सेल टावर और वाई-फ़ाई नेटवर्क जैसे नेटवर्क स्रोतों के आधार पर आपकी जगह का पता लगा सकता है, लेकिन सिर्फ़ तब, जब ऐप्लिकेशन स्क्रीन पर दिखाई दे रहा हो. यह ज़रूरी है कि \'जगह की जानकारी\' वाली ये सेवाएं आपके टीवी पर मौजूद हों और चालू की गई हों ताकि ऐप्लिकेशन उनका इस्तेमाल कर पाए."</string>
     <string name="permdesc_accessCoarseLocation" product="default" msgid="854896049371048754">"यह ऐप्लिकेशन सेल टावर और वाई-फ़ाई नेटवर्क जैसे नेटवर्क स्रोतों के आधार पर आपकी जगह का पता लगा सकता है, लेकिन सिर्फ़ तब, जब ऐप्लिकेशन स्क्रीन पर दिखाई दे रहा हो. यह ज़रूरी है कि \'जगह की जानकारी\' वाली ये सेवाएं आपके फ़ोन में मौजूद हों और चालू की गई हों ताकि ऐप्लिकेशन उनका इस्तेमाल कर पाए."</string>
-    <string name="permlab_accessBackgroundLocation" msgid="3965397804300661062">"बैकग्राउंड में जगह की जानकारी एक्सेस करना"</string>
-    <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"अनुमानित या बिल्कुल सही जगह की जानकारी का एक्सेस करने की अनुमति अलग से दिए जाने पर, बैकग्राउंड में चलने के दौरान ऐप्लिकेशन आपकी जगह की जानकारी एक्सेस कर सकता है."</string>
+    <string name="permlab_accessBackgroundLocation" msgid="3965397804300661062">"बैकग्राउंड में जगह की जानकारी ऐक्सेस करना"</string>
+    <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"अनुमानित या बिल्कुल सही जगह की जानकारी का ऐक्सेस करने की अनुमति अलग से दिए जाने पर, बैकग्राउंड में चलने के दौरान ऐप्लिकेशन आपकी जगह की जानकारी ऐक्सेस कर सकता है."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"अपनी ऑडियो सेटिंग बदलें"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ऐप्स  को वैश्विक ऑडियो सेटिंग, जैसे वॉल्‍यूम और कौन-सा स्पीकर आउटपुट के लिए उपयोग किया गया, संशोधित करने देता है."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"ऑडियो रिकॉर्ड करने"</string>
@@ -451,7 +452,7 @@
     <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"ऐप को डिवाइस के फ़ोन नंबर का इस्तेमाल करने देती है."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टैबलेट को सोने (कम बैटरी मोड) से रोकें"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"टीवी को सोने (कम बैटरी मोड) से रोकें"</string>
-    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"टीवी को सोने (कम बैटरी मोड) से रोकें"</string>
+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को सोने (कम बैटरी मोड) से रोकें"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ऐप्स  को टैबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
     <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"ऐप को टीवी को सोने (कम बैटरी मोड) से रोकने की अनुमति देता है."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ऐप्स  को फ़ोन को प्रयोग में नहीं होने से रोकता है."</string>
@@ -468,9 +469,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>
@@ -484,9 +485,9 @@
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"वाई-फ़ाई  से कनेक्‍ट और डिस्‍कनेक्‍ट करें"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"ऐप्स  को वाई-फ़ाई  पहुंच बिंदुओं से कनेक्ट और डिसकनेक्ट करने और वाई-फ़ाई  नेटवर्क के लिए डिवाइस कॉन्फ़िगरेशन में परिवर्तन करने देता है."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"वाई-फ़ाई मल्‍टीकास्‍ट पाने को अनुमति दें"</string>
-    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"ऐप्स  को वाई-फ़ाई  नेटवर्क पर मल्टीकास्ट पते के उपयोग से केवल आपके टैबलेट पर ही नहीं, बल्कि सभी डिवाइस पर भेजे गए पैकेट प्राप्‍त करने देता है. यह गैर-मल्टीकास्ट मोड से ज़्यादा पावर का उपयोग करता है."</string>
-    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"ऐप को मल्‍टीकास्‍ट पतों का उपयोग करके ना केवल आपके टीवी को, बल्‍कि वाई-फ़ाई पर मौजूद सभी डिवाइसों को पैकेट भेजने और प्राप्‍त करने देती है. इसमें गैर-मल्‍टीकास्‍ट मोड की अपेक्षा ज़्यादा पावर का उपयोग होता है."</string>
-    <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"ऐप्स  को वाई-फ़ाई  नेटवर्क पर मल्टीकास्ट पते के उपयोग से केवल आपके फ़ोन पर ही नहीं, बल्कि सभी डिवाइस पर भेजे गए पैकेट प्राप्‍त करने देता है. यह गैर-मल्टीकास्ट मोड से ज़्यादा पावर का उपयोग करता है."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"एप्लिकेशन को वाई-फ़ाई नेटवर्क पर मल्टीकास्ट पते के इस्तेमाल से सिर्फ़ आपके टैबलेट पर ही नहीं, बल्कि सभी डिवाइस पर भेजे गए पैकेट पाने देता है. यह गैर-मल्टीकास्ट मोड से ज़्यादा पावर का इस्तेमाल करता है."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"ऐप्लिकेशन को मल्‍टीकास्‍ट पतों का उपयोग करके न सिर्फ़ आपके टीवी को, बल्‍कि वाई-फ़ाई पर मौजूद सभी डिवाइसों को पैकेट भेजने और पाने देती है. इसमें गैर-मल्‍टीकास्‍ट मोड की अपेक्षा ज़्यादा पावर का उपयोग होता है."</string>
+    <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"एप्लिकेशन को वाई-फ़ाई  नेटवर्क पर मल्टीकास्ट पते के इस्तेमाल से सिर्फ़ आपके फ़ोन पर ही नहीं, बल्कि सभी डिवाइस पर भेजे गए पैकेट पाने देता है. यह गैर-मल्टीकास्ट मोड से ज़्यादा पावर का इस्तेमाल करता है."</string>
     <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"ब्लूटूथ सेटिंग पर पहुंचें"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"किसी ऐप्स को स्‍थानीय ब्लूटूथ टैबलेट कॉन्‍फ़िगर करने की और रिमोट डिवाइस के साथ खोजने और युग्‍मित करने देता है."</string>
     <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"ऐप को स्‍थानीय ब्‍लूटूथ टीवी कॉन्‍फ़िगर करने देती है और दूरस्‍थ डिवाइसों को खोजने और उनसे युग्‍मित करने देती है."</string>
@@ -504,7 +505,7 @@
     <string name="permlab_nfc" msgid="4423351274757876953">"नियर फ़ील्‍ड कम्‍यूनिकेशन नियंत्रित करें"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"ऐप्स  को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"अपना स्‍क्रीन लॉक अक्षम करें"</string>
-    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ऐप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल खत्म होने पर कीलॉक को फिर से सक्षम कर देता है."</string>
+    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ऐप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा बंद करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल पाते समय फ़ोन, कीलॉक को बंद कर देता है, फिर कॉल खत्म होने पर कीलॉक को फिर से चालू कर देता है."</string>
     <string name="permlab_requestPasswordComplexity" msgid="202650535669249674">"जानें कि स्क्रीन लॉक कितना मुश्किल बनाया गया है"</string>
     <string name="permdesc_requestPasswordComplexity" msgid="4730994229754212347">"यह मंज़ूरी मिलने के बाद ऐप्लिकेशन जान पाता है कि स्क्रीन लॉक कितना मुश्किल (बहुत ज़्यादा, मध्यम, कम या बिल्कुल नहीं) है. इस स्तर से यह पता चलता है कि स्क्रीन लॉक कितना लंबा या किस तरह का है. ऐप्लिकेशन उपयोगकर्ताओं को यह सुझाव भी दे सकता है कि वे स्क्रीन लॉक को एक तय लेवल तक अपडेट करें. लेकिन उपयोगकर्ता इसे बेझिझक अनदेखा करके छोड़ सकते हैं. ध्यान दें कि स्क्रीन लॉक को सादे टेक्स्ट में सेव नहीं किया जाता है इसलिए ऐप्लिकेशन को सटीक पासवर्ड पता नहीं होता है."</string>
     <string name="permlab_useBiometric" msgid="8837753668509919318">"बायोमीट्रिक हार्डवेयर इस्तेमाल करने दें"</string>
@@ -519,8 +520,8 @@
     <string name="permdesc_videoWrite" msgid="5448565757490640841">"इससे ऐप्लिकेशन को आपके वीडियो संग्रह में बदलाव करने की मंज़ूरी दी जाती है."</string>
     <string name="permlab_imagesWrite" msgid="3391306186247235510">"अपने फ़ोटो संग्रह में बदलाव करने की अनुमति दें"</string>
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"इससे ऐप्लिकेशन को आपके फ़ोटो संग्रह में बदलाव करने की मंज़ूरी दी जाती है."</string>
-    <string name="permlab_mediaLocation" msgid="8675148183726247864">"अपने मीडिया संग्रह से जगह की जानकारी एक्सेस करने की अनुमति दें"</string>
-    <string name="permdesc_mediaLocation" msgid="2237023389178865130">"इससे ऐप्लिकेशन को आपके मीडिया संग्रह से जगह की जानकारी एक्सेस करने की अनुमति दी जाती है."</string>
+    <string name="permlab_mediaLocation" msgid="8675148183726247864">"अपने मीडिया संग्रह से जगह की जानकारी ऐक्सेस करने की अनुमति दें"</string>
+    <string name="permdesc_mediaLocation" msgid="2237023389178865130">"इससे ऐप्लिकेशन को आपके मीडिया संग्रह से जगह की जानकारी ऐक्सेस करने की अनुमति दी जाती है."</string>
     <string name="biometric_dialog_default_title" msgid="881952973720613213">"अपनी पहचान की पुष्टि करें"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेयर उपलब्ध नहीं है"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"प्रमाणीकरण रद्द किया गया"</string>
@@ -604,8 +605,8 @@
     <string name="permdesc_sdcardRead" msgid="1804941689051236391">"ऐप्‍लिकेशन को आपकी शेयर की गई मेमोरी की सामग्री पढ़ने देती है."</string>
     <string name="permlab_sdcardWrite" msgid="9220937740184960897">"आपकी शेयर की गई मेमोरी की सामग्री में बदलाव करना या उसे मिटाना"</string>
     <string name="permdesc_sdcardWrite" msgid="2834431057338203959">"ऐप्लिकेशन को आपकी शेयर की गई मेमोरी की सामग्री लिखने देती है."</string>
-    <string name="permlab_use_sip" msgid="2052499390128979920">"SIP कॉल करें/प्राप्‍त करें"</string>
-    <string name="permdesc_use_sip" msgid="2297804849860225257">"ऐप्स को SIP कॉल करने और प्राप्‍त करने देती है."</string>
+    <string name="permlab_use_sip" msgid="2052499390128979920">"SIP कॉल करें/पाएं"</string>
+    <string name="permdesc_use_sip" msgid="2297804849860225257">"ऐप्लिकेशन को SIP कॉल करने और पाने देता है."</string>
     <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"नए टेलिकॉम सिम कनेक्‍शन रजिस्टर करें"</string>
     <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"ऐप को नए टेलिकॉम सिम कनेक्‍शन पंजीकृत करने देती है."</string>
     <string name="permlab_register_call_provider" msgid="108102120289029841">"नए टेलिकॉम कनेक्‍शन रजिस्टर करें"</string>
@@ -615,7 +616,7 @@
     <string name="permlab_bind_incall_service" msgid="6773648341975287125">"इन-कॉल स्क्रीन से सहभागिता करें"</string>
     <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"ऐप को यह नियंत्रित करने देती है कि उपयोगकर्ता को इन-कॉल स्क्रीन कब और कैसी दिखाई देती है."</string>
     <string name="permlab_bind_connection_service" msgid="3557341439297014940">"टेलीफ़ोनी सेवाओं के साथ सहभागिता करें"</string>
-    <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"कॉल करने/प्राप्‍त करने के लिए ऐप्स को टेलीफ़ोनी सेवा के साथ सहभागिता करने दें."</string>
+    <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"कॉल करने/पाने के लिए ऐप्स को टेलीफ़ोनी सेवा के साथ सहभागिता करने दें."</string>
     <string name="permlab_control_incall_experience" msgid="9061024437607777619">"इन कॉल उपयोगकर्ता अनुभव लें"</string>
     <string name="permdesc_control_incall_experience" msgid="915159066039828124">"ऐप को इन कॉल उपयोगकर्ता अनुभव लेने देती है."</string>
     <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"ऐतिहासिक नेटवर्क उपयोग पढें"</string>
@@ -638,7 +639,7 @@
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ऐप्स  को नेटवर्क स्थितियों के अवलोकनों को सुनने देता है. सामान्य ऐप्स  के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"इनपुट डिवाइस कैलिब्रेशन बदलें"</string>
     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ऐप्स को टच स्क्रीन के कैलिब्रेशन पैरामीटर को बदलने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM प्रमाणपत्र एक्सेस करें"</string>
+    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM प्रमाणपत्र ऐक्सेस करें"</string>
     <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"ऐप्लिकेशन को DRM प्रमाणपत्रों का प्रावधान और उपयोग करने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यकता नहीं होना चाहिए."</string>
     <string name="permlab_handoverStatus" msgid="7820353257219300883">"Android बीम ट्रांसफ़र की स्थिति पाएं"</string>
     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"इस ऐप को मौजूदा Android बीम ट्रांसफ़र के बारे में जानकारी पाने की अनुमति दें."</string>
@@ -1135,7 +1136,7 @@
     <string name="whichOpenLinksWith" msgid="6392123355599572804">"इसे इस्तेमाल करके लिंक खोलें"</string>
     <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> इस्तेमाल करके लिंक खोलें"</string>
     <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> इस्तेमाल करके <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलें"</string>
-    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"एक्सेस दें"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ऐक्सेस दें"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"इसके ज़रिये बदलाव करें"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s की मदद से बदलाव करें"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"बदलाव करें"</string>
@@ -1214,9 +1215,9 @@
     <string name="dump_heap_ready_notification" msgid="1162196579925048701">"<xliff:g id="PROC">%1$s</xliff:g> हीप डंप तैयार है"</string>
     <string name="dump_heap_notification_detail" msgid="3993078784053054141">"हीप डंप (Java™ प्रोसेस मेमोरी का स्नैपशॉट) ले लिया गया है. शेयर करने के लिए टैप करें."</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप शेयर करें?"</string>
-    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रिया अपनी <xliff:g id="SIZE">%2$s</xliff:g> की मेमोरी सीमा पार कर चुकी है. एक हीप डंप इसके डेवलपर के साथ शेयर किए जाने के लिए तैयार है. सावधान रहें: इस हीप डंप में कोई ऐसी निजी जानकारी भी शामिल हो सकती है जिसका एक्सेस ऐप्लिकेशन के पास हो."</string>
-    <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रिया अपनी <xliff:g id="SIZE">%2$s</xliff:g> की मेमोरी सीमा पार कर चुकी है. एक हीप डंप शेयर किए जाने के लिए तैयार है. सावधान रहें: इस हीप डंप में कोई ऐसी संवेदनशील निजी जानकारी भी शामिल हो सकती है जिसका एक्सेस प्रोसेस के पास हो. इसमें आपके टाइप किए गए शब्दों का डेटा भी शामिल है."</string>
-    <string name="dump_heap_ready_text" msgid="1778041771455343067">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रिया का हीप डंप शेयर किए जाने के लिए तैयार है. सावधान रहें: इस हीप डंप में कोई ऐसी संवेदनशील निजी जानकारी शामिल हो सकती है जिसका एक्सेस प्रोसेस के पास हो. इसमें आपके टाइप किए गए शब्दों का डेटा भी शामिल है."</string>
+    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रिया अपनी <xliff:g id="SIZE">%2$s</xliff:g> की मेमोरी सीमा पार कर चुकी है. एक हीप डंप इसके डेवलपर के साथ शेयर किए जाने के लिए तैयार है. सावधान रहें: इस हीप डंप में कोई ऐसी निजी जानकारी भी शामिल हो सकती है जिसका ऐक्सेस ऐप्लिकेशन के पास हो."</string>
+    <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रिया अपनी <xliff:g id="SIZE">%2$s</xliff:g> की मेमोरी सीमा पार कर चुकी है. एक हीप डंप शेयर किए जाने के लिए तैयार है. सावधान रहें: इस हीप डंप में कोई ऐसी संवेदनशील निजी जानकारी भी शामिल हो सकती है जिसका ऐक्सेस प्रोसेस के पास हो. इसमें आपके टाइप किए गए शब्दों का डेटा भी शामिल है."</string>
+    <string name="dump_heap_ready_text" msgid="1778041771455343067">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रिया का हीप डंप शेयर किए जाने के लिए तैयार है. सावधान रहें: इस हीप डंप में कोई ऐसी संवेदनशील निजी जानकारी शामिल हो सकती है जिसका ऐक्सेस प्रोसेस के पास हो. इसमें आपके टाइप किए गए शब्दों का डेटा भी शामिल है."</string>
     <string name="sendText" msgid="5209874571959469142">"मैसेज करने के लिए कोई कार्रवाई चुनें"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर वॉल्‍यूम"</string>
     <string name="volume_music" msgid="5421651157138628171">"मीडिया वॉल्‍यूम"</string>
@@ -1376,7 +1377,7 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"दूसरे ऐप्लिकेशन के ऊपर दिखाए जाने का एक्सेस"</string>
+    <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"दूसरे ऐप्लिकेशन के ऊपर दिखाए जाने का ऐक्सेस"</string>
     <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> अन्य ऐप्लिकेशन के ऊपर दिखाई दे रहा है"</string>
     <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्य ऐप पर दिखाई दे रहा है"</string>
     <string name="alert_windows_notification_message" msgid="8917232109522912560">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने और उसे बंद करने के लिए टैप करें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 21fdc2f..38bd8a3 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi pozivi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM-a visokog prioriteta"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Način TTY FULL koji zahtijeva paralelni uređaj"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Način TTY HCO koji zahtijeva paralelni uređaj"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Način TTY VCO koji zahtijeva paralelni uređaj"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 1198610..d146ca7 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Hangpostaüzenetek"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-hívás"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kártya állapota"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Elsődleges SIM-kártya állapota"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner által kért TTY-mód: FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner által kért TTY-mód: HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner által kért TTY-mód: VCO"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 7165df9..91d2552 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ձայնային փոստի հաղորդագրություններ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Զանգեր Wi-Fi-ի միջոցով"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM քարտի կարգավիճակը"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM քարտի բարձր առաջնահերթության ծանուցումներ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Բաժանորդի սարքում ընտրված է հեռատիպի ԲՈԼՈՐԸ ռեժիմը"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Բաժանորդի սարքում ընտրված է հեռատիպի HCO ռեժիմը"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Բաժանորդի սարքում ընտրված է հեռատիպի VCO ռեժիմը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index ca369eb..4a8723b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Notifikasi pesan suara"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Panggilan Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM prioritas tinggi"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Rekan meminta Mode TTY PENUH"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Rekan meminta Mode TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Rekan meminta Mode TTY VCO"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 572313a..16bcd27 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talhólfsskilaboð"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi símtöl"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Staða SIM-korts"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Áríðandi staða SIM-korts"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Jafningi bað um FULLA stillingu fjarrita"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Jafningi bað um HCO-stillingu fjarrita"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Jafningi bað um VCO-stillingu fjarrita"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 6c579b8..8581eca 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messaggi vocali"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chiamate Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stato SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stato SIM con priorità elevata"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer ha richiesto la modalità TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer ha richiesto la modalità TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer ha richiesto la modalità TTY VCO"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 437b31b..dc108b4 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"הודעות קוליות"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏שיחות Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‏סטטוס SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‏סטטוס התראות SIM בעדיפות גבוהה"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏העמית ביקש TTY במצב FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏העמית ביקש TTY במצב HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏העמית ביקש TTY במצב VCO"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index b558a31..5180ab2 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ボイスメール メッセージ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM のステータス"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高優先度: SIM のステータス"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ピアから、TTY モードを FULL にするようリクエストされました"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ピアから、TTYモードをHCOにするようリクエストされました"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ピアから、TTYモードをVCOにするようリクエストされました"</string>
@@ -298,7 +299,7 @@
     <string name="permgrouplab_microphone" msgid="171539900250043464">"マイク"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"音声の録音"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"音声の録音を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
-    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"運動データ"</string>
+    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"身体活動"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"運動データにアクセス"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"運動データへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"カメラ"</string>
@@ -551,11 +552,11 @@
   <string-array name="fingerprint_error_vendor">
   </string-array>
     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"指紋アイコン"</string>
-    <string name="permlab_manageFace" msgid="7262837876352591553">"フェイスアンロック ハードウェアの管理"</string>
+    <string name="permlab_manageFace" msgid="7262837876352591553">"顔認証ハードウェアの管理"</string>
     <string name="permdesc_manageFace" msgid="8919637120670185330">"使用する顔テンプレートの追加や削除を行うメソッドの呼び出しをアプリに許可します。"</string>
-    <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"フェイスアンロック ハードウェアの使用"</string>
-    <string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"フェイスアンロック ハードウェアを認証に使用することをアプリに許可します"</string>
-    <string name="face_recalibrate_notification_name" msgid="1913676850645544352">"フェイスアンロック"</string>
+    <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"顔認証ハードウェアの使用"</string>
+    <string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"顔認証ハードウェアを認証に使用することをアプリに許可します"</string>
+    <string name="face_recalibrate_notification_name" msgid="1913676850645544352">"顔認証"</string>
     <string name="face_recalibrate_notification_title" msgid="4087620069451499365">"顔の再登録"</string>
     <string name="face_recalibrate_notification_content" msgid="5530308842361499835">"認識を改善するには、顔を再登録してください"</string>
     <string name="face_acquired_insufficient" msgid="2767330364802375742">"顔を認識できませんでした。もう一度お試しください。"</string>
@@ -581,15 +582,15 @@
   <string-array name="face_acquired_vendor">
   </string-array>
     <string name="face_error_hw_not_available" msgid="396883585636963908">"顔を確認できません。ハードウェアを利用できません。"</string>
-    <string name="face_error_timeout" msgid="981512090365729465">"フェイスアンロックをもう一度お試しください。"</string>
+    <string name="face_error_timeout" msgid="981512090365729465">"顔認証をもう一度お試しください。"</string>
     <string name="face_error_no_space" msgid="2712120617457553825">"新しい顔データを保存できません。古いデータを削除してください。"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"顔の操作をキャンセルしました。"</string>
-    <string name="face_error_user_canceled" msgid="5317030072349668946">"フェイスアンロックはユーザーによりキャンセルされました。"</string>
+    <string name="face_error_user_canceled" msgid="5317030072349668946">"顔認証はユーザーによりキャンセルされました。"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"試行回数の上限です。後でもう一度お試しください。"</string>
-    <string name="face_error_lockout_permanent" msgid="4723594314443097159">"試行回数が上限を超えました。フェイスアンロックを無効にしました。"</string>
+    <string name="face_error_lockout_permanent" msgid="4723594314443097159">"試行回数が上限を超えたため、顔認証を無効にしました。"</string>
     <string name="face_error_unable_to_process" msgid="4940944939691171539">"顔を確認できません。もう一度お試しください。"</string>
-    <string name="face_error_not_enrolled" msgid="4016937174832839540">"フェイスアンロックを設定していません。"</string>
-    <string name="face_error_hw_not_present" msgid="8302690289757559738">"このデバイスでは、フェイスアンロックはご利用いただけません。"</string>
+    <string name="face_error_not_enrolled" msgid="4016937174832839540">"顔認証を設定していません。"</string>
+    <string name="face_error_hw_not_present" msgid="8302690289757559738">"このデバイスでは、顔認証はご利用いただけません。"</string>
     <string name="face_name_template" msgid="7004562145809595384">"顔 <xliff:g id="FACEID">%d</xliff:g>"</string>
   <string-array name="face_error_vendor">
   </string-array>
@@ -818,7 +819,7 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"もう一度お試しください"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"もう一度お試しください"</string>
     <string name="lockscreen_storage_locked" msgid="9167551160010625200">"すべての機能とデータを利用するにはロック解除"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"フェイスアンロックの最大試行回数を超えました"</string>
+    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"顔認証の最大試行回数を超えました"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIMカードが挿入されていません"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"タブレット内にSIMカードがありません。"</string>
     <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"テレビにSIMカードが挿入されていません。"</string>
@@ -888,7 +889,7 @@
     <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ロック解除エリアを拡大します。"</string>
     <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"スライドロックを解除します。"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"パターンロックを解除します。"</string>
-    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"フェイスアンロックを行います。"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"顔認証を行います。"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PINロックを解除します。"</string>
     <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"SIM PIN のロックを解除します。"</string>
     <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"SIM PUK のロックを解除します。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 3570d4c..2bba8cb 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ხმოვანი ფოსტის შეტყობინებები"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"დარეკვა Wi-Fi-ს მეშვეობით"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM სტატუსი"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"მაღალპრიორიტეტული SIM სტატუსი"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"მოთხოვნილია კვანძი TTY რეჟიმი FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"მოთხოვნილია კვანძი TTY რეჟიმი HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"მოთხოვნილია კვანძი TTY რეჟიმი VCO"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 2ed1e5b..ec0ab3e 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Дауыстық пошта хабарлары"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi қоңыраулары"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM күйі"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM картасы туралы маңызды хабарландырулар"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Пир TTY режимі ТОЛЫҚ сұрады"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Пир TTY режимінің HCO сұрады"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Пир TTY режимінің VCO сұрады"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 02c6ba8..e9a140c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"សារ​ជា​សំឡេង"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ការហៅ​ទូរសព្ទ​តាម Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ស្ថានភាព​ស៊ីម"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ស្ថានភាពស៊ីម​ដែលមាន​អាទិភាព​ខ្ពស់"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode VCO"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 875ecd4..e82d54b 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ಧ್ವನಿಮೇಲ್ ಸಂದೇಶಗಳು"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ಸಿಮ್‌ ಸ್ಥಿತಿ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ಹೆಚ್ಚಿನ ಆದ್ಯತೆಯ ಸಿಮ್ ಸ್ಥಿತಿ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ VCO"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 9077145..4be4bd2 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"음성사서함 메시지"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 통화"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 상태"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"우선순위가 높은 SIM 상태"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"피어가 TTY 모드 FULL을 요청했습니다."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"피어가 TTY 모드 HCO를 요청했습니다."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"피어가 TTY 모드 VCO를 요청했습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 8cac363..6607242 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Үн почтасынын билдирүүлөрү"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi аркылуу чалуу"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-картанын абалы"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM картадагы өтө маанилүү билдирмелер"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer TTY режимин FULL кылууну суранды"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer TTY режимин HCO кылууну суранды"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer TTY режимин VCO кылууну суранды"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 47b0fe4..684adc3 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ຂໍ້ຄວາມສຽງ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ການ​ໂທ Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ສະຖານະ SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ສະຖານະ SIM ຄວາມສຳຄັນສູງ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ໂໝດ TTY ທີ່​ເພື່ອນ​ຂໍ​ນັ້ນ​ເຕັມ​ແລ້ວ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ໂໝດ TTY ທີ່​ເພື່ອນ​ຂໍ HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ໂໝດ TTY ທີ່​ເພື່ອນ​ຂໍ VCO"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6f8e2df..5283f27 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Balso pašto pranešimai"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"„Wi-Fi“ skambinimas"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM būsena"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Didelio prioriteto SIM kortelės būsena"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo VCO"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 253ff72..c93ae1f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Balss pasta ziņojumi"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi zvani"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM kartes statuss"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Augstas prioritātes SIM kartes statuss"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu VCO"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 19c1c85..70ee0ae 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Пораки од говорна пошта"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Повикување преку Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус на SIM-картичка"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Статус на SIM-известувања со висок приоритет"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Рамноправен уред го побара режимот на TTY „FULL“"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Рамноправен уред го побара режимот на TTY „HCO“"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Рамноправен уред го побара режимот на TTY „VCO“"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index b2e9b64..3fb844d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"വോയ്‌സ്‌മെയിൽ സന്ദേശങ്ങൾ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"വൈഫൈ കോളിംഗ്"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"സിം നില"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ഉയർന്ന മുൻഗണനയുള്ള സിം നില"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് \'ഫുൾ\'"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് VCO"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index a229713..254bb0e 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Дуут шуудангийн мессеж"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi дуудлага"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM статус"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Өндөр ач холбогдолтой SIM-н статус"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Хандлагын цэгт хүсэлт тавьсан TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Хандлагын цэгт хүсэлт тавьсан TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Хандлагын цэгт хүсэлт тавьсан TTY Mode VCO"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a86caa5..5fc2310 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"व्हॉइसमेल मेसेज"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"वाय-फाय कॉलिंग"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"सिम स्थिती"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"उच्च प्राधान्य सिम स्थिती"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"समवयस्क व्यक्तीने TTY मोड पूर्ण ची विनंती केली"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"समवयस्क व्यक्तीने TTY मोड HCO ची विनंती केली"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"समवयस्क व्यक्तीने TTY मोड VCO ची विनंती केली"</string>
@@ -302,8 +303,8 @@
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"शारीरिक अ‍ॅक्टिव्हिटी अ‍ॅक्सेस करा"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमची शारीरिक अ‍ॅक्टिव्हिटी अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"कॅमेरा"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"चित्रे घेण्याची आणि व्हिडिओ रेकॉर्ड"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला फोटो घेऊ आणि व्हिडिओ रेकॉर्ड करू द्यायचे?"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"चित्रे काढण्याची आणि व्हिडिओ रेकॉर्ड करण्याची"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला फोटो काढू आणि व्हिडिओ रेकॉर्ड करू द्यायचे?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"कॉल लॉग"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"फोन कॉल लॉग वाचा आणि लिहा"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमचे फोन कॉल लॉग अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index c18e078..7d1b76c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesej mel suara"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Panggilan Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM keutamaan tinggi"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Rakan meminta Mod TTY PENUH"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Rakan meminta Mod TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Rakan meminta Mod TTY VCO"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 55e7b01..e037b70 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"အသံမေးလ် မက်ဆေ့ဂျ်များ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi ခေါ်ဆိုမှု"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ဆင်းမ်ကဒ် အခြေအနေ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"အထူးဦးစားပေး ဆင်းမ်ကတ်အခြေအနေ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"အခြားစက်မှ TTY မုဒ် FULL ပြုရန် တောင်းဆို၏"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"အခြားစက်မှ TTY မုဒ် HCO ပြုရန် တောင်းဆို၏"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY မုဒ် VCO ပြုရန် အခြားစက်မှ တောင်းဆို၏"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a589389..c75c8d1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talepostmeldinger"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-anrop"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-status er satt til høy prioritet"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Motpart ba om TTY-modus FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Motpart ba om TTY-modus HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Motpart ba om TTY-modus VCO"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 89e75b4..1422caa 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"भ्वाइस मेल सन्देशहरू"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi कल"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM को स्थिति"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"उच्च प्राथमिकता रहेको SIM को स्थिति"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"सहकर्मी अनुरोध गरियो। TTY मोड पूर्ण"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"सहकर्मी अनुरोध गरियो। TTY मोड HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"सहकर्मी अनुरोध गरियो। TTY मोड VCO"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 4194eb1..c668abe 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemailberichten"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Bellen via wifi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Simkaartstatus"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Meldingen met hoge prioriteit voor de simkaartstatus"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Door peer aangevraagde TTY-modus VOL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Door peer aangevraagde TTY-modus HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Door peer aangevraagde TTY-modus VCO"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 0f3472c..940fdc16 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ଭଏସମେଲ୍‍ ମେସେଜ୍‍"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ୱାଇ-ଫାଇ କଲିଙ୍ଗ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM ଷ୍ଟାଟସ୍"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ଉଚ୍ଚ ପ୍ରାଥମିକତା SIM ସ୍ଥିତି"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ପୀଆର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ FULL ଅଟେ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ HCO ଅଟେ"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ VCO ଅଟେ"</string>
@@ -1659,7 +1660,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ଆପଣଙ୍କ ଅନଲକ୍‍ ପାଟର୍ନକୁ ଆପଣ <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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ବାହାର କରନ୍ତୁ"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"ମାତ୍ରା ବଢ଼ାଇ ସୁପାରିସ ସ୍ତର ବଢ଼ାଉଛନ୍ତି? \n\n ଲମ୍ବା ସମୟ ପର୍ଯ୍ୟନ୍ତ ଉଚ୍ଚ ଶବ୍ଦରେ ଶୁଣିଲେ ଆପଣଙ୍କ ଶ୍ରବଣ ଶକ୍ତି ଖରାପ ହୋଇପାରେ।"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"ମାତ୍ରା ବଢ଼ାଇ ସୁପାରିଶ ସ୍ତର ବଢ଼ାଉଛନ୍ତି? \n\n ଲମ୍ବା ସମୟ ପର୍ଯ୍ୟନ୍ତ ଉଚ୍ଚ ଶବ୍ଦରେ ଶୁଣିଲେ ଆପଣଙ୍କ ଶ୍ରବଣ ଶକ୍ତି ଖରାପ ହୋଇପାରେ।"</string>
     <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"ଆକ୍ସେସବିଲିଟି ଶର୍ଟକଟ୍‍ ବ୍ୟବହାର କରିବେ?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"ସର୍ଟକଟ୍‌ ଅନ୍‌ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍‍ ବଟନ୍‍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଆକ୍ସେସବିଲିଟି ବୈଶିଷ୍ଟ ଆରମ୍ଭ ହେବ।\n\n ସମ୍ପ୍ରତି ଆକ୍ସେସବିଲିଟି ବୈଶିଷ୍ଟ୍ୟ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ସେଟିଙ୍ଗ ଓ ଆକ୍ସେସବିଲିଟିରେ ଆପଣ ବୈଶିଷ୍ଟ୍ୟ ବଦଳାଇ ପାରିବେ।"</string>
     <string name="disable_accessibility_shortcut" msgid="627625354248453445">"ଶର୍ଟକଟ୍‍ ବନ୍ଦ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 8245546..ddf2fc1 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ਵੌਇਸਮੇਲ ਸੁਨੇਹੇ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ਸਿਮ ਅਵਸਥਾ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ਉੱਚ ਤਰਜੀਹੀ ਸਿਮ ਸਥਿਤੀ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ਪੀਅਰ ਨੇ TTY Mode FULL ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ਪੀਅਰ ਨੇ TTY Mode HCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ਪੀਅਰ ਨੇ TTY Mode VCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 054a456..69fc0e6 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Wiadomości poczty głosowej"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Połączenia przez Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stan karty SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stan karty SIM – wysoki priorytet"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Drugie urządzenie zażądało trybu „TTY pełny”"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Drugie urządzenie zażądało trybu „TTY HCO”"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Drugie urządzenie zażądało trybu „TTY VCO”"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 742fa81..f29ea42 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens do correio de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status do chip"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status de prioridade alta do chip"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"TTD modo COMPLETO solicitado"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"TTD modo HCO solicitado"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTD modo VCO solicitado"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 85fb7fd..696f2f1 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens de correio de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estado do SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado do SIM de elevada prioridade"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"O par solicitou o modo COMPLETO de teletipo"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"O par solicitou o modo HCO de teletipo"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"O par solicitou o modo VCO de teletipo"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 742fa81..f29ea42 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens do correio de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status do chip"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status de prioridade alta do chip"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"TTD modo COMPLETO solicitado"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"TTD modo HCO solicitado"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTD modo VCO solicitado"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 2f464e9..d80a7ba 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesaje din mesageria vocală"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Apelare prin Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Starea cardului SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notificări de la SIM cu prioritate ridicată"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Cealaltă persoană a solicitat modul TTY cu setarea COMPLET"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Cealaltă persoană a solicitat modul TTY cu setarea HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Cealaltă persoană a solicitat modul TTY cu setarea VCO"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c4b61b2..410f4b9 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Голосовые сообщения"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Звонки по Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карты"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Важные уведомления SIM-карты"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"На устройстве абонента выбран режим телетайпа \"ВСЕ\""</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"На устройстве абонента выбран режим телетайпа HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"На устройстве абонента выбран режим телетайпа VCO"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index ddeb94b..a39cb6e 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"හඬ තැපැල් පණිවිඩ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi ඇමතීම"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM තත්ත්වය"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ඉහළ ප්‍රමුඛතා SIM තත්ත්වය"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"සම ඉල්ලීම් කළ TTY ප්‍රකාරය පූර්ණයි"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"සම ඉල්ලීම් කළ TTY ප්‍රකාරය HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"සම ඉල්ලීම් කළ TTY ප්‍රකාරය VCO"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4d19308..d8a7561 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Správy hlasovej schránky"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Volanie cez Wi‑Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stav SIM karty"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stav SIM karty: vysoká priorita"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Používateľ, s ktorým komunikujete, požiadal o režim FULL textového telefónu"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Používateľ, s ktorým komunikujete, požiadal o režim HCO textového telefónu"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Používateľ, s ktorým komunikujete, požiadal o režim VCO textového telefónu"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index b2b3109..7e12c2c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Sporočila v odzivniku"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Klicanje prek Wi-Fi-ja"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stanje kartice SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stanje kartice SIM z visoko stopnjo prednosti"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Enakovredna naprava je zahtevala način TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Enakovredna naprava je zahtevala način TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Enakovredna naprava je zahtevala način TTY VCO"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index afed336..a958d1b 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesazhet e postës zanore"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Telefonata me Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Statusi i kartës SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Statusi i kartës SIM me përparësi të lartë"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Homologu yt kërkoi modalitet \"TTY\" të plotë"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Homologu kërkoi modalitet \"TTY\" të llojit \"HCO\""</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Homologu yt kërkoi modalitet \"TTY\" të llojit \"VCO\""</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 110b31d..1adede3 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Поруке говорне поште"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Позивање преко Wi-Fi мреже"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-а"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Обавештења SIM картице са статусом „висок приоритет“"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Корисник захтева ПОТПУН режим TTY"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Корисник захтева ПРЕНОС ЗВУКА за режим TTY"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Корисник захтева ПРЕНОС ГЛАСА за режим TTY"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bc1752e..434f36a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Röstmeddelanden"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-samtal"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status för SIM-kort"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-aviseringar med hög prioritet"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer-enheten begärde texttelefonläget FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer-enheten begärde texttelefonläget HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer-enheten begärde texttelefonläget VCO"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 92510ea..8f18ceb 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ujumbe wa sauti"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Kupiga simu kupitia Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Hali ya SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Hali ya SIM ya kipaumbele cha juu"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Hali ya TTY iliyoombwa na mtandao mwenza KAMILI"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Hali ya TTY iliyoombwa na mtandao mwenza HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Hali ya TTY iliyoombwa na mtandao mwenza VCO"</string>
@@ -364,7 +365,7 @@
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"Wezesha mtindo wa gari"</string>
     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Inaruhusu programu kuwawezesha mtindo wa gari."</string>
     <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"funga programu zingine"</string>
-    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Inaruhusu programu kukamilisha michakato ya usuli ya programu nyingine. Hii inaweza kusababisha programu nyingine kukoma kufanyakazi."</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Huruhusu programu kukamilisha michakato ya chinichini ya programu nyingine. Hii inaweza kusababisha programu nyingine kuacha kufanya kazi."</string>
     <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"Programu hii inaweza kuonekana juu ya programu zingine"</string>
     <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"Programu hii inaweza kuonekana juu ya programu zingine au sehemu zingine za skrini. Hii huenda ikaathiri matumizi ya kawaida ya programu na kubadilisha jinsi ambavyo programu zingine zinavyoonekana."</string>
     <string name="permlab_runInBackground" msgid="7365290743781858803">"tumia chini chini"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 8ddcfe6..d211e90 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"குரலஞ்சல் செய்திகள்"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"வைஃபை அழைப்பு"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"சிம் நிலை"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"அதிக முன்னுரிமையுடைய சிம்மின் நிலை"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"TTY Mode FULLஐ இணைச் செயல்பாடு கோரியது"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"TTY Mode HCOஐ இணைச் செயல்பாடு கோரியது"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY Mode VCOஐ இணைச் செயல்பாடு கோரியது"</string>
@@ -366,7 +367,7 @@
     <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"பிற பயன்பாடுகளை மூடுதல்"</string>
     <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"பிற பயன்பாடுகளின் பின்புலச் செயல்முறைகளை நிறுத்த ஆப்ஸை அனுமதிக்கிறது. இதனால் பிற பயன்பாடுகள் இயங்குவதை நிறுத்தலாம்."</string>
     <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"இந்த ஆப்ஸ் பிற பயன்பாடுகளின் மேலே தோன்றலாம்"</string>
-    <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"இந்த ஆப்ஸ் பிற பயன்பாடுகளின் மேலே அல்லது திரையின் பிற பகுதிகளில் தோன்றலாம். இது வழக்கமான பயன்பாட்டு உபயோகத்தில் குறுக்கிட்டு, பிற பயன்பாடுகள் தோன்றும் விதத்தை மாற்றக்கூடும்."</string>
+    <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"இந்த ஆப்ஸ் பிற பயன்பாடுகளின் மேலே அல்லது திரையின் பிற பகுதிகளில் தோன்றலாம். இது வழக்கமான ஆப்ஸ் உபயோகத்தில் குறுக்கிட்டு, பிற பயன்பாடுகள் தோன்றும் விதத்தை மாற்றக்கூடும்."</string>
     <string name="permlab_runInBackground" msgid="7365290743781858803">"பின்னணியில் இயக்கு"</string>
     <string name="permdesc_runInBackground" msgid="7370142232209999824">"இந்த ஆப்ஸ், பின்னணியில் இயங்கலாம். இதனால் பேட்டரி விரைவாகத் தீர்ந்துவிடக்கூடும்."</string>
     <string name="permlab_useDataInBackground" msgid="8694951340794341809">"பின்னணியில் தரவைப் பயன்படுத்து"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 649e17c..e6a3daf 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"వాయిస్ మెయిల్ సందేశాలు"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi కాలింగ్"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM స్థితి"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"అధిక ప్రాధాన్యత గల SIM స్థితి"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"అవతలి వారు FULL TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"అవతలి వారు HCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"అవతలి వారు VCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4e69430..045ea3e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ข้อความเสียง"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"การโทรผ่าน Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"สถานะซิม"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"สถานะซิมลำดับความสำคัญสูง"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"เต็ม\""</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"HCO\""</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"VCO\""</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6843528..6dcc40c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mga mensahe sa voicemail"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Pagtawag gamit ang Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status ng SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority na status ng SIM"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Hiniling ng peer ang TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Hiniling ng peer ang TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Hiniling ng peer ang TTY Mode VCO"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 3592df9..c0303ac 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Sesli mesajlar"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Kablosuz çağrı"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM durumu"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Yüksek öncelikli SIM durumu"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Karşı taraf TTY Modunu TAM yaptı"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Karşı taraf TTY Modunu HCO yaptı"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Karşı taraf TTY Modunu VCO yaptı"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 347c81f..3437b51 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Повідомлення голосової пошти"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Дзвінки через Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карти"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Високопріоритетні сповіщення із SIM-карти"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Пристрій змінив режим TTY на FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Пристрій змінив режим TTY на HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Пристрій змінив режим TTY на VCO"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 3fd6fe7..83c3199 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"صوتی میل پیغامات"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏Wi-Fi کالنگ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‏SIM کا اسٹیٹس"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‏اعلی ترجیحی SIM کی صورتحال"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏ہمسر نے TTY وضع مکمل کی درخواست کی"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏ہمسر نے TTY وضع HCO کی درخواست کی"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏ہمسر نے TTY وضع VCO کی درخواست کی"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 85ebe00..0425010 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ovozli xabarlar"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi chaqiruv"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM karta holati"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM kartadagi muhim bildirishnomalar"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Teng huquqli ishtirokchi teletayp rejimini FULL (to‘liq) qilib o‘zgartirdi"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Teng huquqli ishtirokchi teletayp rejimini HCO (eshitadi, gapirolmaydi) qilib o‘zgartirdi"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Teng huquqli ishtirokchi teletayp rejimini VCO (gapiradi, eshitolmaydi) qilib o‘zgartirdi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 78c4290..4f7b4fe 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Thư thoại"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Gọi qua Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Trạng thái SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Trạng thái SIM có mức ưu tiên cao"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ ĐẦY ĐỦ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ VCO"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1012337..765e1db 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"语音邮件"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"WLAN 通话"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡状态"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高优先顺序 SIM 卡状态"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"对方请求使用“TTY 完整”模式"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"对方请求使用“TTY HCO”模式"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"对方请求使用“TTY VCO”模式"</string>
@@ -298,9 +299,9 @@
     <string name="permgrouplab_microphone" msgid="171539900250043464">"麦克风"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"录制音频"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;录音吗?"</string>
-    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"健身运动"</string>
-    <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"访问您的健身运动"</string>
-    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问您的健身运动吗?"</string>
+    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"身体活动"</string>
+    <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"获取您的身体活动数据"</string>
+    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;获取您的身体活动数据吗?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"相机"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"拍摄照片和录制视频"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;拍摄照片和录制视频吗?"</string>
@@ -429,8 +430,8 @@
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"此应用可随时使用麦克风进行录音。"</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"向 SIM 卡发送命令"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"允许应用向SIM卡发送命令(此权限具有很高的危险性)。"</string>
-    <string name="permlab_activityRecognition" msgid="3634590230567608356">"识别健身运动"</string>
-    <string name="permdesc_activityRecognition" msgid="3143453925156552894">"此应用可以识别您的健身运动。"</string>
+    <string name="permlab_activityRecognition" msgid="3634590230567608356">"识别身体活动"</string>
+    <string name="permdesc_activityRecognition" msgid="3143453925156552894">"此应用可以识别您的身体活动。"</string>
     <string name="permlab_camera" msgid="3616391919559751192">"拍摄照片和视频"</string>
     <string name="permdesc_camera" msgid="5392231870049240670">"此应用可随时使用相机拍摄照片和录制视频。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"控制振动"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 884772e..4124079 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"留言訊息"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡狀態"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"重要 SIM 卡狀態"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"對方曾要求 TTY 完整模式"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"對方曾要求 TTY 模式 (HCO)"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"對方曾要求 TTY 模式 (VCO)"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 580a1dc..1f7b3e2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"語音留言"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡狀態"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高優先順序 SIM 卡狀態"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"通訊對象要求使用 TTY 的 FULL 模式"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"通訊對象要求使用 TTY 的 HCO 模式"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"通訊對象要求使用 TTY 的 VCO 模式"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c4f8823..c58c77c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Imilayezo yevoyisimeyili"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Ukushaya kwe-Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Isimo se-SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Isimo se-SIM esiphezulu kakhulu"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Umngani ucele imodi ye-TTY ephelele"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Umngani ucele imodi ye-TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Umngani ucele imodi ye-TTY VCO"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dce4bf3..4d6e7da 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1301,6 +1301,9 @@
     <!-- Whether to use the strict phone number matcher in Kazakhstan. -->
     <bool name="config_use_strict_phone_number_comparation_for_kazakhstan">true</bool>
 
+    <!-- The character count of the minimum match for comparison phone numbers -->
+    <integer name="config_phonenumber_compare_min_match">7</integer>
+
     <!-- Display low battery warning when battery level dips to this value.
          Also, the battery stats are flushed to disk when we hit this level.  -->
     <integer name="config_criticalBatteryWarningLevel">5</integer>
@@ -1700,11 +1703,16 @@
         <!-- Add packages here -->
     </string-array>
 
+    <!-- The set of system packages on device that are queryable regardless of the contents of their
+         manifest. -->
     <string-array name="config_forceQueryablePackages" translatable="false">
         <item>com.android.settings</item>
         <!-- Add packages here -->
     </string-array>
 
+    <!-- If true, will force all packages on any system partition as queryable regardless of the
+         contents of their manifest. -->
+    <bool name="config_forceSystemPackagesQueryable">false</bool>
 
     <!-- Component name of the default wallpaper. This will be ImageWallpaper if not
          specified -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 913001c..40f20ab 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -187,6 +187,9 @@
     <string name="notification_channel_wfc">Wi-Fi calling</string>
     <!-- Telephony notification channel name for a channel containing SIM notifications -->
     <string name="notification_channel_sim">SIM status</string>
+    <!-- Telephony notification channel name for a channel containing high priority SIM notifications -->
+    <string name="notification_channel_sim_high_prio">High priority SIM status</string>
+
 
     <!-- Displayed to tell the user that peer changed TTY mode -->
     <string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 123deeb..4094bf4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -320,6 +320,7 @@
   <java-symbol type="bool" name="config_use_strict_phone_number_comparation" />
   <java-symbol type="bool" name="config_use_strict_phone_number_comparation_for_russia" />
   <java-symbol type="bool" name="config_use_strict_phone_number_comparation_for_kazakhstan" />
+  <java-symbol type="integer" name="config_phonenumber_compare_min_match" />
   <java-symbol type="bool" name="config_single_volume" />
   <java-symbol type="bool" name="config_voice_capable" />
   <java-symbol type="bool" name="config_requireCallCapableAccountForHandle" />
@@ -653,6 +654,7 @@
   <java-symbol type="string" name="notification_channel_voice_mail" />
   <java-symbol type="string" name="notification_channel_wfc" />
   <java-symbol type="string" name="notification_channel_sim" />
+  <java-symbol type="string" name="notification_channel_sim_high_prio" />
   <java-symbol type="string" name="SetupCallDefault" />
   <java-symbol type="string" name="accept" />
   <java-symbol type="string" name="activity_chooser_view_see_all" />
@@ -787,6 +789,7 @@
   <java-symbol type="string" name="emergency_calls_only" />
   <java-symbol type="array" name="config_ephemeralResolverPackage" />
   <java-symbol type="array" name="config_forceQueryablePackages" />
+  <java-symbol type="bool" name="config_forceSystemPackagesQueryable" />
   <java-symbol type="string" name="eventTypeAnniversary" />
   <java-symbol type="string" name="eventTypeBirthday" />
   <java-symbol type="string" name="eventTypeCustom" />
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index f9e3798..6e65df1 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -17,7 +17,6 @@
 
 import static org.junit.Assert.*;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.argThat;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -41,7 +40,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
@@ -49,7 +47,6 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Tests for v2 HAL RadioModule.
@@ -293,61 +290,6 @@
         }
         ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet,
                 removedSet);
-        verify(clientMock).onProgramListUpdated(argThat(new ChunkMatcher(expectedChunk)));
+        verify(clientMock).onProgramListUpdated(expectedChunk);
     }
-
-    // TODO(b/130750904): Remove this class and replace "argThat(new ChunkMatcher(chunk))" with
-    // "eq(chunk)".
-    //
-    // Ideally, this class wouldn't exist, but currently RadioManager.ProgramInfo#hashCode() can
-    // return different values for objects that satisfy ProgramInfo#equals(). As a short term
-    // workaround, this class performs the O(N^2) comparison between the Chunks' mModified sets.
-    //
-    // To test if ProgramInfo#hashCode() has been fixed, remove commenting from
-    // testProgramInfoHashCode() below.
-    private class ChunkMatcher implements ArgumentMatcher<ProgramList.Chunk> {
-        private final ProgramList.Chunk mExpected;
-
-        ChunkMatcher(ProgramList.Chunk expected) {
-            mExpected = expected;
-        }
-
-        @Override
-        public boolean matches(ProgramList.Chunk actual) {
-            if ((mExpected.isPurge() != actual.isPurge())
-                    || (mExpected.isComplete() != actual.isComplete())
-                    || (!mExpected.getRemoved().equals(actual.getRemoved()))) {
-                return false;
-            }
-            Set<RadioManager.ProgramInfo> expectedModified = mExpected.getModified();
-            Set<RadioManager.ProgramInfo> actualModified = new HashSet<>(actual.getModified());
-            if (expectedModified.size() != actualModified.size()) {
-                return false;
-            }
-            for (RadioManager.ProgramInfo expectedInfo : expectedModified) {
-                boolean found = false;
-                for (RadioManager.ProgramInfo actualInfo : actualModified) {
-                    if (expectedInfo.equals(actualInfo)) {
-                        found = true;
-                        actualModified.remove(actualInfo);
-                        break;
-                    }
-                }
-                if (!found) {
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
-
-    // @Test
-    // public void testProgramInfoHashCode() {
-    //     RadioManager.ProgramInfo info1 = TestUtils.makeProgramInfo(
-    //         ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
-    //     RadioManager.ProgramInfo info2 = TestUtils.makeProgramInfo(
-    //         ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
-    //     assertEquals(info1, info2);
-    //     assertEquals(info1.hashCode(), info2.hashCode());
-    // }
 }
diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java
index 0eba2ed..46873b9 100644
--- a/core/tests/coretests/src/android/os/ParcelTest.java
+++ b/core/tests/coretests/src/android/os/ParcelTest.java
@@ -43,8 +43,8 @@
 
         // WorkSource can be updated.
         p.writeInterfaceToken(INTERFACE_TOKEN_1);
-        assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1));
-        assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid());
+        assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_2));
+        assertEquals(WORK_SOURCE_2, p.readCallingWorkSourceUid());
 
         // WorkSource can be updated to unset value.
         assertEquals(true, p.replaceCallingWorkSourceUid(Binder.UNSET_WORKSOURCE));
@@ -56,18 +56,16 @@
     @Test
     public void testCallingWorkSourceUidAfterEnforce() {
         Parcel p = Parcel.obtain();
-        // Write headers manually so that we do not invoke #writeInterfaceToken.
-        p.writeInt(1);  // strict mode header
-        p.writeInt(WORK_SOURCE_1);  // worksource header.
-        p.writeString(INTERFACE_TOKEN_1);  // interface token.
+        p.writeInterfaceToken(INTERFACE_TOKEN_1);
+        assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1));
         p.setDataPosition(0);
 
         p.enforceInterface(INTERFACE_TOKEN_1);
         assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid());
 
         // WorkSource can be updated.
-        assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1));
-        assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid());
+        assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_2));
+        assertEquals(WORK_SOURCE_2, p.readCallingWorkSourceUid());
 
         p.recycle();
     }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 88bda9d..89ba3df 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -721,7 +721,8 @@
                  Settings.Secure.BIOMETRIC_DEBUG_ENABLED,
                  Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED,
                  Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED,
-                 Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED);
+                 Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED,
+                 Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED);
 
     @Test
     public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index cadf37e..9d09830 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -17,8 +17,11 @@
 package android.view;
 
 import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
 import static android.view.MotionEvent.TOOL_TYPE_FINGER;
 
+import static junit.framework.Assert.assertTrue;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
@@ -77,4 +80,62 @@
                 0, 0, 0, 0, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, displayId, 0);
         assertNull(motionEvent);
     }
+
+    @Test
+    public void testCalculatesCursorPositionForTouchscreenEvents() {
+        final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+                ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
+        event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+
+        assertTrue(Float.isNaN(event.getXCursorPosition()));
+        assertTrue(Float.isNaN(event.getYCursorPosition()));
+    }
+
+    @Test
+    public void testCalculatesCursorPositionForSimpleMouseEvents() {
+        final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+                ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
+        event.setSource(InputDevice.SOURCE_MOUSE);
+
+        assertEquals(30, event.getXCursorPosition(), 0.1);
+        assertEquals(50, event.getYCursorPosition(), 0.1);
+    }
+
+    @Test
+    public void testCalculatesCursorPositionForSimpleMouseEventsWithOffset() {
+        final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+                ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
+        event.offsetLocation(10 /* deltaX */, 20 /* deltaY */);
+        event.setSource(InputDevice.SOURCE_MOUSE);
+
+        assertEquals(40, event.getXCursorPosition(), 0.1);
+        assertEquals(70, event.getYCursorPosition(), 0.1);
+    }
+
+
+    @Test
+    public void testCalculatesCursorPositionForMultiTouchMouseEvents() {
+        final int pointerCount = 2;
+        final PointerProperties[] properties = new PointerProperties[pointerCount];
+        final PointerCoords[] coords = new PointerCoords[pointerCount];
+
+        for (int i = 0; i < pointerCount; ++i) {
+            properties[i] = new PointerProperties();
+            properties[i].id = i;
+            properties[i].toolType = MotionEvent.TOOL_TYPE_FINGER;
+
+            coords[i] = new PointerCoords();
+            coords[i].x = 20 + i * 20;
+            coords[i].y = 60 - i * 20;
+        }
+
+        final MotionEvent event = MotionEvent.obtain(0 /* downTime */,
+                0 /* eventTime */, ACTION_POINTER_DOWN, pointerCount, properties, coords,
+                0 /* metaState */, 0 /* buttonState */, 1 /* xPrecision */, 1 /* yPrecision */,
+                0 /* deviceId */, 0 /* edgeFlags */, InputDevice.SOURCE_MOUSE,
+                0 /* flags */);
+
+        assertEquals(30, event.getXCursorPosition(), 0.1);
+        assertEquals(50, event.getYCursorPosition(), 0.1);
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
index a935737..dc9208d 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -268,4 +268,144 @@
         assertEquals(20, entry.mCount);
         assertEquals(2000 * 1000, entry.mTotalTime); // Micro seconds
     }
+
+// -------------------- Aggregate  Wakelock Stats Tests --------------------
+    @SmallTest
+    public void testAggregateStatsEmpty() throws Exception {
+        KernelWakelockStats staleStats = new KernelWakelockStats();
+
+        byte[] buffer = new byte[0];
+        WakeLockInfo[] wlStats = new WakeLockInfo[0];
+
+        readKernelWakelockStats(staleStats, buffer, wlStats);
+
+        assertTrue(staleStats.isEmpty());
+    }
+
+    @SmallTest
+    public void testAggregateStatsNoNativeWakelocks() throws Exception {
+        KernelWakelockStats staleStats = new KernelWakelockStats();
+
+        byte[] buffer = new ProcFileBuilder()
+                .addLine("Wakelock", 34, 123) // Milliseconds
+                .getBytes();
+        WakeLockInfo[] wlStats = new WakeLockInfo[0];
+
+        readKernelWakelockStats(staleStats, buffer, wlStats);
+
+        assertEquals(1, staleStats.size());
+
+        assertTrue(staleStats.containsKey("Wakelock"));
+
+        KernelWakelockStats.Entry entry = staleStats.get("Wakelock");
+        assertEquals(34, entry.mCount);
+        assertEquals(1000 * 123, entry.mTotalTime);  // Microseconds
+    }
+
+    @SmallTest
+    public void testAggregateStatsNoKernelWakelocks() throws Exception {
+        KernelWakelockStats staleStats = new KernelWakelockStats();
+
+        byte[] buffer = new byte[0];
+        WakeLockInfo[] wlStats = new WakeLockInfo[1];
+        wlStats[0] = createWakeLockInfo("WakeLock", 10, 1000);  // Milliseconds
+
+        readKernelWakelockStats(staleStats, buffer, wlStats);
+
+        assertEquals(1, staleStats.size());
+
+        assertTrue(staleStats.containsKey("WakeLock"));
+
+        KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
+        assertEquals(10, entry.mCount);
+        assertEquals(1000 * 1000, entry.mTotalTime);  // Microseconds
+    }
+
+    @SmallTest
+    public void testAggregateStatsBothKernelAndNativeWakelocks() throws Exception {
+        KernelWakelockStats staleStats = new KernelWakelockStats();
+
+        byte[] buffer = new ProcFileBuilder()
+                .addLine("WakeLock1", 34, 123)  // Milliseconds
+                .getBytes();
+        WakeLockInfo[] wlStats = new WakeLockInfo[1];
+        wlStats[0] = createWakeLockInfo("WakeLock2", 10, 1000); // Milliseconds
+
+        readKernelWakelockStats(staleStats, buffer, wlStats);
+
+        assertEquals(2, staleStats.size());
+
+        assertTrue(staleStats.containsKey("WakeLock1"));
+        KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
+        assertEquals(34, entry1.mCount);
+        assertEquals(123 * 1000, entry1.mTotalTime);  // Microseconds
+
+        assertTrue(staleStats.containsKey("WakeLock2"));
+        KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
+        assertEquals(10, entry2.mCount);
+        assertEquals(1000 * 1000, entry2.mTotalTime);  // Microseconds
+    }
+
+    @SmallTest
+    public void testAggregateStatsUpdate() throws Exception {
+        KernelWakelockStats staleStats = new KernelWakelockStats();
+
+        byte[] buffer = new ProcFileBuilder()
+                .addLine("WakeLock1", 34, 123)  // Milliseconds
+                .addLine("WakeLock2", 46, 345)  // Milliseconds
+                .getBytes();
+        WakeLockInfo[] wlStats = new WakeLockInfo[2];
+        wlStats[0] = createWakeLockInfo("WakeLock3", 10, 1000); // Milliseconds
+        wlStats[1] = createWakeLockInfo("WakeLock4", 20, 2000); // Milliseconds
+
+        readKernelWakelockStats(staleStats, buffer, wlStats);
+
+        assertEquals(4, staleStats.size());
+
+        assertTrue(staleStats.containsKey("WakeLock1"));
+        assertTrue(staleStats.containsKey("WakeLock2"));
+        assertTrue(staleStats.containsKey("WakeLock3"));
+        assertTrue(staleStats.containsKey("WakeLock4"));
+
+        KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
+        assertEquals(34, entry1.mCount);
+        assertEquals(123 * 1000, entry1.mTotalTime); // Microseconds
+
+        KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
+        assertEquals(46, entry2.mCount);
+        assertEquals(345 * 1000, entry2.mTotalTime); // Microseconds
+
+        KernelWakelockStats.Entry entry3 = staleStats.get("WakeLock3");
+        assertEquals(10, entry3.mCount);
+        assertEquals(1000 * 1000, entry3.mTotalTime); // Microseconds
+
+        KernelWakelockStats.Entry entry4 = staleStats.get("WakeLock4");
+        assertEquals(20, entry4.mCount);
+        assertEquals(2000 * 1000, entry4.mTotalTime); // Microseconds
+
+        buffer = new ProcFileBuilder()
+                .addLine("WakeLock1", 45, 789)  // Milliseconds
+                .addLine("WakeLock1", 56, 123)  // Milliseconds
+                .getBytes();
+        wlStats = new WakeLockInfo[1];
+        wlStats[0] = createWakeLockInfo("WakeLock4", 40, 4000); // Milliseconds
+
+        readKernelWakelockStats(staleStats, buffer, wlStats);
+
+        assertEquals(2, staleStats.size());
+
+        assertTrue(staleStats.containsKey("WakeLock1"));
+        assertTrue(staleStats.containsKey("WakeLock4"));
+
+        assertFalse(staleStats.containsKey("WakeLock2"));
+        assertFalse(staleStats.containsKey("WakeLock3"));
+
+        entry1 = staleStats.get("WakeLock1");
+        assertEquals(45 + 56, entry1.mCount);
+        assertEquals((789 + 123) * 1000, entry1.mTotalTime);  // Microseconds
+
+        entry2 = staleStats.get("WakeLock4");
+        assertEquals(40, entry2.mCount);
+        assertEquals(4000 * 1000, entry4.mTotalTime); // Microseconds
+    }
 }
diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp
new file mode 100644
index 0000000..12a2b08
--- /dev/null
+++ b/core/tests/overlaytests/device/Android.bp
@@ -0,0 +1,26 @@
+// 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.
+
+android_test {
+    name: "OverlayDeviceTests",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    static_libs: ["androidx.test.rules"],
+    test_suites: ["device-tests"],
+    data: [
+        ":OverlayDeviceTests_AppOverlayOne",
+        ":OverlayDeviceTests_AppOverlayTwo",
+        ":OverlayDeviceTests_FrameworkOverlay",
+    ],
+}
diff --git a/core/tests/overlaytests/device/Android.mk b/core/tests/overlaytests/device/Android.mk
deleted file mode 100644
index c6d2a51..0000000
--- a/core/tests/overlaytests/device/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := OverlayDeviceTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_REQUIRED_MODULES := \
-    OverlayDeviceTests_AppOverlayOne \
-    OverlayDeviceTests_AppOverlayTwo \
-    OverlayDeviceTests_FrameworkOverlay
-include $(BUILD_PACKAGE)
-
-# Include to build test-apps.
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
diff --git a/core/tests/overlaytests/device/test-apps/Android.mk b/core/tests/overlaytests/device/test-apps/Android.mk
deleted file mode 100644
index 9af9f444..0000000
--- a/core/tests/overlaytests/device/test-apps/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-include $(call all-subdir-makefiles)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
new file mode 100644
index 0000000..da3aa00
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "OverlayDeviceTests_AppOverlayOne",
+    sdk_version: "current",
+
+    aaptflags: ["--no-resource-removal"],
+}
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
deleted file mode 100644
index fa15241..0000000
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT_FLAGS := --no-resource-removal
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
new file mode 100644
index 0000000..215b66da3
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "OverlayDeviceTests_AppOverlayTwo",
+    sdk_version: "current",
+
+    aaptflags: ["--no-resource-removal"],
+}
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
deleted file mode 100644
index ada9b3c..0000000
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT_FLAGS := --no-resource-removal
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp
new file mode 100644
index 0000000..50dbc6f
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp
@@ -0,0 +1,21 @@
+// 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.
+
+android_test {
+    name: "OverlayDeviceTests_FrameworkOverlay",
+    sdk_version: "current",
+    certificate: "platform",
+
+    aaptflags: ["--no-resource-removal"],
+}
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
deleted file mode 100644
index e4819e1..0000000
--- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := OverlayDeviceTests_FrameworkOverlay
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_CERTIFICATE := platform
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT_FLAGS := --no-resource-removal
-include $(BUILD_PACKAGE)
diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index 39bb84a..cb30b3f 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -177,4 +177,40 @@
         assertArrayEquals(new Long[] { 1L, 2L, 3L, 4L },
                 concatElements(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L }));
     }
+
+    public void testConcatElements_threeWay() {
+        String[] array1 = { "1", "2" };
+        String[] array2 = { "3", "4" };
+        String[] array3 = { "5", "6" };
+        String[] expectation = {"1", "2", "3", "4", "5", "6"};
+
+        String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3);
+        assertArrayEquals(expectation, concatResult);
+    }
+
+
+    public void testConcatElements_threeWayWithNull() {
+        String[] array1 = { "1", "2" };
+        String[] array2 = null;
+        String[] array3 = { "5", "6" };
+        String[] expectation = {"1", "2", "5", "6"};
+
+        String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3);
+        assertArrayEquals(expectation, concatResult);
+    }
+
+    public void testConcatElements_zeroElements() {
+        String[] expectation = new String[0];
+
+        String[] concatResult = ArrayUtils.concatElements(String.class);
+        assertArrayEquals(expectation, concatResult);
+    }
+
+    public void testConcatElements_oneNullElement() {
+        String[] expectation = new String[0];
+
+        String[] concatResult = ArrayUtils.concatElements(String.class, null);
+        assertArrayEquals(expectation, concatResult);
+    }
+
 }
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 3361fa2..1d294d5 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -27,7 +27,7 @@
 
 /**
  * RectF holds four float coordinates for a rectangle. The rectangle is
- * represented by the coordinates of its 4 edges (left, top, right bottom).
+ * represented by the coordinates of its 4 edges (left, top, right, bottom).
  * These fields can be accessed directly. Use width() and height() to retrieve
  * the rectangle's width and height. Note: most methods do not check to see that
  * the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp
new file mode 100644
index 0000000..aedb752
--- /dev/null
+++ b/libs/hostgraphics/Android.bp
@@ -0,0 +1,24 @@
+cc_library_host_static {
+    name: "libhostgraphics",
+
+    srcs: [
+        ":libui_host_common",
+    ],
+
+    include_dirs: [
+        // Here we override all the headers automatically included with frameworks/native/include.
+        // When frameworks/native/include will be removed from the list of automatic includes.
+        // We will have to copy necessary headers with a pre-build step (generated headers).
+        ".",
+        "frameworks/native/libs/nativebase/include",
+        "frameworks/native/libs/nativewindow/include",
+        "frameworks/native/libs/arect/include",
+    ],
+    export_include_dirs: ["."],
+
+    target: {
+        windows: {
+            enabled: true,
+        }
+    },
+}
\ No newline at end of file
diff --git a/libs/hostgraphics/gui/IGraphicBufferProducer.h b/libs/hostgraphics/gui/IGraphicBufferProducer.h
new file mode 100644
index 0000000..0042213
--- /dev/null
+++ b/libs/hostgraphics/gui/IGraphicBufferProducer.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H
+#define ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class IGraphicBufferProducer : virtual public RefBase {
+public:
+    enum class DisconnectMode {
+        // Disconnect only the specified API.
+        Api,
+        // Disconnect any API originally connected from the process calling disconnect.
+        AllLocal
+    };
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H
diff --git a/libs/hostgraphics/gui/Surface.h b/libs/hostgraphics/gui/Surface.h
new file mode 100644
index 0000000..de1ba00
--- /dev/null
+++ b/libs/hostgraphics/gui/Surface.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_SURFACE_H
+#define ANDROID_GUI_SURFACE_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <ui/ANativeObjectBase.h>
+#include <utils/RefBase.h>
+#include <system/window.h>
+
+namespace android {
+
+class Surface : public ANativeObjectBase<ANativeWindow, Surface, RefBase> {
+public:
+    explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer,
+                     bool controlledByApp = false) {
+        ANativeWindow::perform = hook_perform;
+    }
+    static bool isValid(const sp<Surface>& surface) { return surface != nullptr; }
+    void allocateBuffers() {}
+
+    uint64_t getNextFrameNumber() const { return 0; }
+
+    int setScalingMode(int mode) { return 0; }
+
+    virtual int disconnect(int api,
+                           IGraphicBufferProducer::DisconnectMode mode =
+                                   IGraphicBufferProducer::DisconnectMode::Api) {
+        return 0;
+    }
+
+    virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) {
+        // TODO: implement this
+        return 0;
+    }
+    virtual int unlockAndPost() { return 0; }
+    virtual int query(int what, int* value) const { return 0; }
+
+protected:
+    virtual ~Surface() {}
+
+    static int hook_perform(ANativeWindow* window, int operation, ...) { return 0; }
+
+private:
+    // can't be copied
+    Surface& operator=(const Surface& rhs);
+    Surface(const Surface& rhs);
+};
+
+} // namespace android
+
+#endif  // ANDROID_GUI_SURFACE_H
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 8aee8f5..8eb5e3d 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -20,6 +20,7 @@
 #include "Debug.h"
 #include "TreeInfo.h"
 #include "VectorDrawable.h"
+#include "private/hwui/WebViewFunctor.h"
 #ifdef __ANDROID__
 #include "renderthread/CanvasContext.h"
 #else
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index f01b1bf..54ac0bd 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -454,7 +454,7 @@
 // Canvas draw operations: Geometry
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
+void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint,
                             SkCanvas::PointMode mode) {
     if (CC_UNLIKELY(count < 2 || paint.nothingToDraw())) return;
     // convert the floats into SkPoints
@@ -464,109 +464,142 @@
         pts[i].set(points[0], points[1]);
         points += 2;
     }
-    mCanvas->drawPoints(mode, count, pts.get(), *filterPaint(paint));
+
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawPoints(mode, count, pts.get(), p);
+    });
 }
 
-void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
-    mCanvas->drawPoint(x, y, *filterPaint(paint));
+void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) {
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawPoint(x, y, p);
+    });
 }
 
-void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
-    this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kPoints_PointMode);
+void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) {
+    this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
 }
 
 void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
-                          const SkPaint& paint) {
-    mCanvas->drawLine(startX, startY, stopX, stopY, *filterPaint(paint));
+                          const Paint& paint) {
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawLine(startX, startY, stopX, stopY, p);
+    });
 }
 
-void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
+void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
     if (CC_UNLIKELY(count < 4 || paint.nothingToDraw())) return;
-    this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kLines_PointMode);
+    this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
 }
 
-void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
+void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
-    mCanvas->drawRect({left, top, right, bottom}, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawRect({left, top, right, bottom}, p);
+    });
 }
 
-void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
+void SkiaCanvas::drawRegion(const SkRegion& region, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
-    mCanvas->drawRegion(region, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawRegion(region, p);
+    });
 }
 
 void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
-                               const SkPaint& paint) {
+                               const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
-    mCanvas->drawRoundRect(rect, rx, ry, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawRoundRect(rect, rx, ry, p);
+    });
 }
 
 void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
-                                const SkPaint& paint) {
-    mCanvas->drawDRRect(outer, inner, *filterPaint(paint));
+                                const Paint& paint) {
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawDRRect(outer, inner, p);
+    });
 }
 
-void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
+void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) {
     if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
-    mCanvas->drawCircle(x, y, radius, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawCircle(x, y, radius, p);
+    });
 }
 
-void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
-    mCanvas->drawOval(oval, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawOval(oval, p);
+    });
 }
 
 void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
-                         float sweepAngle, bool useCenter, const SkPaint& paint) {
+                         float sweepAngle, bool useCenter, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
-    if (fabs(sweepAngle) >= 360.0f) {
-        mCanvas->drawOval(arc, *filterPaint(paint));
-    } else {
-        mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, *filterPaint(paint));
-    }
+    apply_looper(&paint, [&](const SkPaint& p) {
+        if (fabs(sweepAngle) >= 360.0f) {
+            mCanvas->drawOval(arc, p);
+        } else {
+            mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, p);
+        }
+    });
 }
 
-void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+void SkiaCanvas::drawPath(const SkPath& path, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
         return;
     }
-    mCanvas->drawPath(path, *filterPaint(paint));
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawPath(path, p);
+    });
 }
 
-void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
-    mCanvas->drawVertices(vertices, mode, *filterPaint(paint));
+void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const Paint& paint) {
+    apply_looper(&paint, [&](const SkPaint& p) {
+        mCanvas->drawVertices(vertices, mode, p);
+    });
 }
 
 // ----------------------------------------------------------------------------
 // Canvas draw operations: Bitmaps
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
-    mCanvas->drawImage(bitmap.makeImage(), left, top, filterPaint(paint));
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
+    auto image = bitmap.makeImage();
+    apply_looper(paint, [&](const SkPaint& p) {
+        mCanvas->drawImage(image, left, top, &p);
+    });
 }
 
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) {
+    auto image = bitmap.makeImage();
     SkAutoCanvasRestore acr(mCanvas, true);
     mCanvas->concat(matrix);
-    mCanvas->drawImage(bitmap.makeImage(), 0, 0, filterPaint(paint));
+    apply_looper(paint, [&](const SkPaint& p) {
+        mCanvas->drawImage(image, 0, 0, &p);
+    });
 }
 
 void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                             float srcBottom, float dstLeft, float dstTop, float dstRight,
-                            float dstBottom, const SkPaint* paint) {
+                            float dstBottom, const Paint* paint) {
+    auto image = bitmap.makeImage();
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
 
-    mCanvas->drawImageRect(bitmap.makeImage(), srcRect, dstRect, filterPaint(paint),
-                           SkCanvas::kFast_SrcRectConstraint);
+    apply_looper(paint, [&](const SkPaint& p) {
+        mCanvas->drawImageRect(image, srcRect, dstRect, &p, SkCanvas::kFast_SrcRectConstraint);
+    });
 }
 
 void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
-                                const float* vertices, const int* colors, const SkPaint* paint) {
+                                const float* vertices, const int* colors, const Paint* paint) {
     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
     const int indexCount = meshWidth * meshHeight * 6;
     uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
@@ -640,20 +673,20 @@
 #endif
 
     // cons-up a shader for the bitmap
-    PaintCoW paintCoW(paint);
-    SkPaint& tmpPaint = paintCoW.writeable();
-
-    sk_sp<SkImage> image = bitmap.makeImage();
-    sk_sp<SkShader> shader = image->makeShader();
-    tmpPaint.setShader(std::move(shader));
-
-    mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate,
-                          *filterPaint(std::move(paintCoW)));
+    Paint pnt;
+    if (paint) {
+        pnt = *paint;
+    }
+    pnt.setShader(bitmap.makeImage()->makeShader());
+    auto v = builder.detach();
+    apply_looper(&pnt, [&](const SkPaint& p) {
+        mCanvas->drawVertices(v, SkBlendMode::kModulate, p);
+    });
 }
 
 void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
-                               const SkPaint* paint) {
+                               const Paint* paint) {
     SkCanvas::Lattice lattice;
     NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
 
@@ -674,8 +707,10 @@
 
     lattice.fBounds = nullptr;
     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-
-    mCanvas->drawImageLattice(bitmap.makeImage().get(), lattice, dst, filterPaint(paint));
+    auto image = bitmap.makeImage();
+    apply_looper(paint, [&](const SkPaint& p) {
+        mCanvas->drawImageLattice(image.get(), lattice, dst, &p);
+    });
 }
 
 double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) {
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 799a891..ec83a19 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -22,8 +22,10 @@
 #include "RenderNode.h"
 #include "VectorDrawable.h"
 #include "hwui/Canvas.h"
+#include "hwui/Paint.h"
 
 #include <SkCanvas.h>
+#include "src/core/SkArenaAlloc.h"
 
 #include <cassert>
 #include <optional>
@@ -99,39 +101,39 @@
     virtual void drawColor(int color, SkBlendMode mode) override;
     virtual void drawPaint(const SkPaint& paint) override;
 
-    virtual void drawPoint(float x, float y, const SkPaint& paint) override;
-    virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawPoint(float x, float y, const Paint& paint) override;
+    virtual void drawPoints(const float* points, int count, const Paint& paint) override;
     virtual void drawLine(float startX, float startY, float stopX, float stopY,
-                          const SkPaint& paint) override;
-    virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
+                          const Paint& paint) override;
+    virtual void drawLines(const float* points, int count, const Paint& paint) override;
     virtual void drawRect(float left, float top, float right, float bottom,
-                          const SkPaint& paint) override;
-    virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
+                          const Paint& paint) override;
+    virtual void drawRegion(const SkRegion& region, const Paint& paint) override;
     virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
-                               const SkPaint& paint) override;
+                               const Paint& paint) override;
 
    virtual void drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
-                               const SkPaint& paint) override;
+                               const Paint& paint) override;
 
-    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
+    virtual void drawCircle(float x, float y, float radius, const Paint& paint) override;
     virtual void drawOval(float left, float top, float right, float bottom,
-                          const SkPaint& paint) override;
+                          const Paint& paint) override;
     virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
-                         float sweepAngle, bool useCenter, const SkPaint& paint) override;
-    virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
-    virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override;
+                         float sweepAngle, bool useCenter, const Paint& paint) override;
+    virtual void drawPath(const SkPath& path, const Paint& paint) override;
+    virtual void drawVertices(const SkVertices*, SkBlendMode, const Paint& paint) override;
 
-    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
-    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
+    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) override;
+    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) override;
     virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                             float srcBottom, float dstLeft, float dstTop, float dstRight,
-                            float dstBottom, const SkPaint* paint) override;
+                            float dstBottom, const Paint* paint) override;
     virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
                                 const float* vertices, const int* colors,
-                                const SkPaint* paint) override;
+                                const Paint* paint) override;
     virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
-                               const SkPaint* paint) override;
+                               const Paint* paint) override;
     virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override;
 
     virtual bool drawTextAbsolutePos() const override { return true; }
@@ -208,6 +210,35 @@
      */
     PaintCoW&& filterPaint(PaintCoW&& paint) const;
 
+    template <typename Proc> void apply_looper(const Paint* paint, Proc proc) {
+        SkPaint skp;
+        SkDrawLooper* looper = nullptr;
+        if (paint) {
+            skp = *filterPaint(paint);
+            looper = paint->getLooper();
+        }
+        if (looper) {
+            SkSTArenaAlloc<256> alloc;
+            SkDrawLooper::Context* ctx = looper->makeContext(&alloc);
+            if (ctx) {
+                SkDrawLooper::Context::Info info;
+                for (;;) {
+                    SkPaint p = skp;
+                    if (!ctx->next(&info, &p)) {
+                        break;
+                    }
+                    mCanvas->save();
+                    mCanvas->translate(info.fTranslate.fX, info.fTranslate.fY);
+                    proc(p);
+                    mCanvas->restore();
+                }
+            }
+        } else {
+            proc(skp);
+        }
+    }
+
+
 private:
     struct SaveRec {
         int saveCount;
@@ -222,7 +253,7 @@
     void recordClip(const T&, SkClipOp);
     void applyPersistentClips(size_t clipStartIndex);
 
-    void drawPoints(const float* points, int count, const SkPaint& paint, SkCanvas::PointMode mode);
+    void drawPoints(const float* points, int count, const Paint& paint, SkCanvas::PointMode mode);
 
     class Clip;
 
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 89ad1b9..f91d178 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -17,6 +17,7 @@
 #include "VectorDrawable.h"
 
 #include <utils/Log.h>
+#include "hwui/Paint.h"
 #include "PathParser.h"
 #include "SkColorFilter.h"
 #include "SkImageInfo.h"
@@ -458,8 +459,12 @@
         mStagingCache.dirty = false;
     }
 
-    SkPaint paint;
-    getPaintFor(&paint, mStagingProperties);
+    SkPaint skp;
+    getPaintFor(&skp, mStagingProperties);
+    Paint paint;
+    paint.setFilterQuality(skp.getFilterQuality());
+    paint.setColorFilter(skp.refColorFilter());
+    paint.setAlpha(skp.getAlpha());
     outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0, mStagingCache.bitmap->width(),
                           mStagingCache.bitmap->height(), mStagingProperties.getBounds().left(),
                           mStagingProperties.getBounds().top(),
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index a48c860..b98ffca 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -34,7 +34,7 @@
 }
 
 static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness,
-                              const SkPaint& paint, Canvas* canvas) {
+                              const Paint& paint, Canvas* canvas) {
     const SkScalar strokeWidth = fmax(thickness, 1.0f);
     const SkScalar bottom = top + strokeWidth;
     canvas->drawRect(left, top, right, bottom, paint);
@@ -182,7 +182,7 @@
 void Canvas::drawDoubleRoundRectXY(float outerLeft, float outerTop, float outerRight,
                             float outerBottom, float outerRx, float outerRy, float innerLeft,
                             float innerTop, float innerRight, float innerBottom, float innerRx,
-                            float innerRy, const SkPaint& paint) {
+                            float innerRy, const Paint& paint) {
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect outer = SkRect::MakeLTRB(outerLeft, outerTop, outerRight, outerBottom);
     SkRect inner = SkRect::MakeLTRB(innerLeft, innerTop, innerRight, innerBottom);
@@ -198,7 +198,7 @@
 void Canvas::drawDoubleRoundRectRadii(float outerLeft, float outerTop, float outerRight,
                             float outerBottom, const float* outerRadii, float innerLeft,
                             float innerTop, float innerRight, float innerBottom,
-                            const float* innerRadii, const SkPaint& paint) {
+                            const float* innerRadii, const Paint& paint) {
     static_assert(sizeof(SkVector) == sizeof(float) * 2);
     if (CC_UNLIKELY(paint.nothingToDraw())) return;
     SkRect outer = SkRect::MakeLTRB(outerLeft, outerTop, outerRight, outerBottom);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index ee4fa1d6..b90a4a3 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -217,37 +217,37 @@
     virtual void drawPaint(const SkPaint& paint) = 0;
 
     // Geometry
-    virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
-    virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) = 0;
+    virtual void drawPoint(float x, float y, const Paint& paint) = 0;
+    virtual void drawPoints(const float* points, int floatCount, const Paint& paint) = 0;
     virtual void drawLine(float startX, float startY, float stopX, float stopY,
-                          const SkPaint& paint) = 0;
-    virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) = 0;
+                          const Paint& paint) = 0;
+    virtual void drawLines(const float* points, int floatCount, const Paint& paint) = 0;
     virtual void drawRect(float left, float top, float right, float bottom,
-                          const SkPaint& paint) = 0;
-    virtual void drawRegion(const SkRegion& region, const SkPaint& paint) = 0;
+                          const Paint& paint) = 0;
+    virtual void drawRegion(const SkRegion& region, const Paint& paint) = 0;
     virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
-                               const SkPaint& paint) = 0;
+                               const Paint& paint) = 0;
     virtual void drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
-                                const SkPaint& paint) = 0;
-    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
+                                const Paint& paint) = 0;
+    virtual void drawCircle(float x, float y, float radius, const Paint& paint) = 0;
     virtual void drawOval(float left, float top, float right, float bottom,
-                          const SkPaint& paint) = 0;
+                          const Paint& paint) = 0;
     virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
-                         float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
-    virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
-    virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) = 0;
+                         float sweepAngle, bool useCenter, const Paint& paint) = 0;
+    virtual void drawPath(const SkPath& path, const Paint& paint) = 0;
+    virtual void drawVertices(const SkVertices*, SkBlendMode, const Paint& paint) = 0;
 
     // Bitmap-based
-    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) = 0;
-    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) = 0;
+    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) = 0;
+    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) = 0;
     virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                             float srcBottom, float dstLeft, float dstTop, float dstRight,
-                            float dstBottom, const SkPaint* paint) = 0;
+                            float dstBottom, const Paint* paint) = 0;
     virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
-                                const float* vertices, const int* colors, const SkPaint* paint) = 0;
+                                const float* vertices, const int* colors, const Paint* paint) = 0;
     virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
-                               const SkPaint* paint) = 0;
+                               const Paint* paint) = 0;
 
     virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0;
     virtual void drawPicture(const SkPicture& picture) = 0;
@@ -281,12 +281,12 @@
     void drawDoubleRoundRectXY(float outerLeft, float outerTop, float outerRight,
                                 float outerBottom, float outerRx, float outerRy, float innerLeft,
                                 float innerTop, float innerRight, float innerBottom, float innerRx,
-                                float innerRy, const SkPaint& paint);
+                                float innerRy, const Paint& paint);
 
     void drawDoubleRoundRectRadii(float outerLeft, float outerTop, float outerRight,
                                 float outerBottom, const float* outerRadii, float innerLeft,
                                 float innerTop, float innerRight, float innerBottom,
-                                const float* innerRadii, const SkPaint& paint);
+                                const float* innerRadii, const Paint& paint);
 
     static int GetApiLevel() { return sApiLevel; }
 
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 9b2fa9d..281ecd2 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -21,6 +21,7 @@
 
 #include <cutils/compiler.h>
 
+#include <SkDrawLooper.h>
 #include <SkFont.h>
 #include <SkPaint.h>
 #include <string>
@@ -58,12 +59,17 @@
     SkFont& getSkFont() { return mFont; }
     const SkFont& getSkFont() const { return mFont; }
 
+    SkDrawLooper* getLooper() const { return mLooper.get(); }
+    void setLooper(sk_sp<SkDrawLooper> looper) { mLooper = std::move(looper); }
+
     // These shadow the methods on SkPaint, but we need to so we can keep related
     // attributes in-sync.
 
     void reset();
     void setAntiAlias(bool);
 
+    bool nothingToDraw() const { return !mLooper && SkPaint::nothingToDraw(); }
+
     // End method shadowing
 
     void setLetterSpacing(float letterSpacing) { mLetterSpacing = letterSpacing; }
@@ -146,6 +152,7 @@
  
 private:
     SkFont mFont;
+    sk_sp<SkDrawLooper> mLooper;
 
     float mLetterSpacing = 0;
     float mWordSpacing = 0;
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index 2f2d575..fa2674f 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -34,6 +34,7 @@
 Paint::Paint(const Paint& paint)
         : SkPaint(paint)
         , mFont(paint.mFont)
+        , mLooper(paint.mLooper)
         , mLetterSpacing(paint.mLetterSpacing)
         , mWordSpacing(paint.mWordSpacing)
         , mFontFeatureSettings(paint.mFontFeatureSettings)
@@ -52,6 +53,7 @@
 Paint& Paint::operator=(const Paint& other) {
     SkPaint::operator=(other);
     mFont = other.mFont;
+    mLooper = other.mLooper;
     mLetterSpacing = other.mLetterSpacing;
     mWordSpacing = other.mWordSpacing;
     mFontFeatureSettings = other.mFontFeatureSettings;
@@ -69,6 +71,7 @@
 bool operator==(const Paint& a, const Paint& b) {
     return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
            a.mFont == b.mFont &&
+           a.mLooper == b.mLooper && 
            a.mLetterSpacing == b.mLetterSpacing && a.mWordSpacing == b.mWordSpacing &&
            a.mFontFeatureSettings == b.mFontFeatureSettings &&
            a.mMinikinLocaleListId == b.mMinikinLocaleListId &&
@@ -83,6 +86,7 @@
 
     mFont = SkFont();
     mFont.setEdging(SkFont::Edging::kAlias);
+    mLooper.reset();
 
     mStrikeThru = false;
     mUnderline = false;
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 96b17e1..b017384 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -33,6 +33,10 @@
     }
 }
 
+static inline SkScalar isIntegerAligned(SkScalar x) {
+    return fabsf(roundf(x) - x) <= NON_ZERO_EPSILON;
+}
+
 // Disable filtering when there is no scaling in screen coordinates and the corners have the same
 // fraction (for translate) or zero fraction (for any other rect-to-rect transform).
 static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, const SkRect& dstRect) {
@@ -62,10 +66,10 @@
     if (requiresIntegerTranslate) {
         // Device rect and source rect should be integer aligned to ensure there's no difference
         // in how nearest-neighbor sampling is resolved.
-        return !(MathUtils::isZero(SkScalarFraction(srcRect.x())) &&
-                 MathUtils::isZero(SkScalarFraction(srcRect.y())) &&
-                 MathUtils::isZero(SkScalarFraction(dstDevRect.x())) &&
-                 MathUtils::isZero(SkScalarFraction(dstDevRect.y())));
+        return !(isIntegerAligned(srcRect.x()) &&
+                 isIntegerAligned(srcRect.y()) &&
+                 isIntegerAligned(dstDevRect.x()) &&
+                 isIntegerAligned(dstDevRect.y()));
     } else {
         // As long as src and device rects are translated by the same fractional amount,
         // filtering won't be needed
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index c7d5f31..d7076d4 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "SkiaDisplayList.h"
+#include "FunctorDrawable.h"
 
 #include "DumpOpsCanvas.h"
 #ifdef __ANDROID__ // Layoutlib does not support SkiaPipeline
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index b791037..e3c3273 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include "FunctorDrawable.h"
 #include "RecordingCanvas.h"
 #include "RenderNodeDrawable.h"
 #include "TreeInfo.h"
@@ -34,6 +33,7 @@
 }
 
 class Outline;
+struct WebViewSyncData;
 
 namespace VectorDrawable {
 class Tree;
@@ -42,6 +42,8 @@
 
 namespace skiapipeline {
 
+class FunctorDrawable;
+
 class SkiaDisplayList {
 public:
     size_t getUsedSize() { return allocator.usedSize() + mDisplayList.usedSize(); }
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 38ef131..0db5133 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -15,7 +15,7 @@
  */
 
 #include "SkiaRecordingCanvas.h"
-
+#include "hwui/Paint.h"
 #include <SkImagePriv.h>
 #include "CanvasTransform.h"
 #ifdef __ANDROID__ // Layoutlib does not support Layers
@@ -197,9 +197,37 @@
     return filterPaint(std::move(paint));
 }
 
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
+static SkDrawLooper* get_looper(const Paint* paint) {
+    return paint ? paint->getLooper() : nullptr;
+}
+
+template <typename Proc>
+void applyLooper(SkDrawLooper* looper, const SkPaint& paint, Proc proc) {
+    if (looper) {
+        SkSTArenaAlloc<256> alloc;
+        SkDrawLooper::Context* ctx = looper->makeContext(&alloc);
+        if (ctx) {
+            SkDrawLooper::Context::Info info;
+            for (;;) {
+                SkPaint p = paint;
+                if (!ctx->next(&info, &p)) {
+                    break;
+                }
+                proc(info.fTranslate.fX, info.fTranslate.fY, p);
+            }
+        }
+    } else {
+        proc(0, 0, paint);
+    }
+}
+
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
     sk_sp<SkImage> image = bitmap.makeImage();
-    mRecorder.drawImage(image, left, top, filterBitmap(paint), bitmap.palette());
+
+    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+        mRecorder.drawImage(image, left + x, top + y, &p, bitmap.palette());
+    });
+
     // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
     // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
     // when this function ends.
@@ -208,12 +236,16 @@
     }
 }
 
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) {
     SkAutoCanvasRestore acr(&mRecorder, true);
     concat(matrix);
 
     sk_sp<SkImage> image = bitmap.makeImage();
-    mRecorder.drawImage(image, 0, 0, filterBitmap(paint), bitmap.palette());
+
+    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+        mRecorder.drawImage(image, x, y, &p, bitmap.palette());
+    });
+
     if (!bitmap.isImmutable() && image.get() && !image->unique()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
@@ -221,13 +253,17 @@
 
 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                                      float srcBottom, float dstLeft, float dstTop, float dstRight,
-                                     float dstBottom, const SkPaint* paint) {
+                                     float dstBottom, const Paint* paint) {
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
 
     sk_sp<SkImage> image = bitmap.makeImage();
-    mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint),
-                            SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+
+    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+        mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), &p,
+                                SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+    });
+
     if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
         !dstRect.isEmpty()) {
         mDisplayList->mMutableImages.push_back(image.get());
@@ -236,7 +272,7 @@
 
 void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
                                         float dstTop, float dstRight, float dstBottom,
-                                        const SkPaint* paint) {
+                                        const Paint* paint) {
     SkCanvas::Lattice lattice;
     NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
 
@@ -264,8 +300,11 @@
         filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality);
     }
     sk_sp<SkImage> image = bitmap.makeImage();
-    mRecorder.drawImageLattice(image, lattice, dst, filterBitmap(std::move(filteredPaint)),
-                               bitmap.palette());
+
+    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+        mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), &p, bitmap.palette());
+    });
+
     if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index c42cea3..bd5274c 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -45,14 +45,14 @@
 
     virtual uirenderer::DisplayList* finishRecording() override;
 
-    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
-    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
+    virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) override;
+    virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) override;
     virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
                             float srcBottom, float dstLeft, float dstTop, float dstRight,
-                            float dstBottom, const SkPaint* paint) override;
+                            float dstBottom, const Paint* paint) override;
     virtual void drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& chunk,
                                float dstLeft, float dstTop, float dstRight, float dstBottom,
-                               const SkPaint* paint) override;
+                               const Paint* paint) override;
     virtual double drawAnimatedImage(AnimatedImageDrawable* animatedImage) override;
 
     virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d97c5ed..d19351b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -450,20 +450,38 @@
     waitOnFences();
 
     bool requireSwap = false;
+    int error = OK;
     bool didSwap =
             mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
 
     mIsDirty = false;
 
     if (requireSwap) {
-        if (!didSwap) {  // some error happened
+        bool didDraw = true;
+        // Handle any swapchain errors
+        error = mNativeSurface->getAndClearError();
+        if (error == TIMED_OUT) {
+            // Try again
+            mRenderThread.postFrameCallback(this);
+            // But since this frame didn't happen, we need to mark full damage in the swap
+            // history
+            didDraw = false;
+
+        } else if (error != OK || !didSwap) {
+            // Unknown error, abandon the surface
             setSurface(nullptr);
+            didDraw = false;
         }
+
         SwapHistory& swap = mSwapHistory.next();
-        swap.damage = windowDirty;
+        if (didDraw) {
+            swap.damage = windowDirty;
+        } else {
+            swap.damage = SkRect::MakeWH(INT_MAX, INT_MAX);
+        }
         swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
         swap.vsyncTime = mRenderThread.timeLord().latestVsync();
-        if (mNativeSurface.get()) {
+        if (didDraw) {
             int durationUs;
             nsecs_t dequeueStart = mNativeSurface->getLastDequeueStartTime();
             if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0910828..f9b9310 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -22,6 +22,7 @@
 #include "FrameMetricsReporter.h"
 #include "IContextFactory.h"
 #include "IRenderPipeline.h"
+#include "JankTracker.h"
 #include "LayerUpdateQueue.h"
 #include "Lighting.h"
 #include "ReliableSurface.h"
@@ -150,8 +151,6 @@
 
     void setContentDrawBounds(const Rect& bounds) { mContentDrawBounds = bounds; }
 
-    RenderState& getRenderState() { return mRenderThread.renderState(); }
-
     void addFrameMetricsObserver(FrameMetricsObserver* observer) {
         if (mFrameMetricsReporter.get() == nullptr) {
             mFrameMetricsReporter.reset(new FrameMetricsReporter());
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 159cf49..da27c1f 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -289,6 +289,10 @@
     if (mPBufferSurface == EGL_NO_SURFACE && !EglExtensions.surfacelessContext) {
         EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
         mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
+        LOG_ALWAYS_FATAL_IF(mPBufferSurface == EGL_NO_SURFACE,
+                            "Failed to create a pixel buffer display=%p, "
+                            "mEglConfig=%p, error=%s",
+                            mEglDisplay, mEglConfig, eglErrorString());
     }
 }
 
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index ad1fc49..a44b804 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -87,21 +87,21 @@
 }
 
 int ReliableSurface::reserveNext() {
+    if constexpr (DISABLE_BUFFER_PREFETCH) {
+        return OK;
+    }
     {
         std::lock_guard _lock{mMutex};
         if (mReservedBuffer) {
             ALOGW("reserveNext called but there was already a buffer reserved?");
             return OK;
         }
-        if (mInErrorState) {
+        if (mBufferQueueState != OK) {
             return UNKNOWN_ERROR;
         }
         if (mHasDequeuedBuffer) {
             return OK;
         }
-        if constexpr (DISABLE_BUFFER_PREFETCH) {
-            return OK;
-        }
     }
 
     // TODO: Update this to better handle when requested dimensions have changed
@@ -165,10 +165,11 @@
         }
     }
 
+
     int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
     if (result != OK) {
         ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
-        *buffer = acquireFallbackBuffer();
+        *buffer = acquireFallbackBuffer(result);
         *fenceFd = -1;
         return *buffer ? OK : INVALID_OPERATION;
     } else {
@@ -201,9 +202,9 @@
     return windowBuffer == scratchBuffer;
 }
 
-ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() {
+ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) {
     std::lock_guard _lock{mMutex};
-    mInErrorState = true;
+    mBufferQueueState = error;
 
     if (mScratchBuffer) {
         return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index 0bfc72e..41fc35e 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -43,6 +43,12 @@
 
     uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); }
 
+    int getAndClearError() {
+        int ret = mBufferQueueState;
+        mBufferQueueState = OK;
+        return ret;
+    }
+
 private:
     const sp<Surface> mSurface;
 
@@ -55,10 +61,10 @@
     ANativeWindowBuffer* mReservedBuffer = nullptr;
     base::unique_fd mReservedFenceFd;
     bool mHasDequeuedBuffer = false;
-    bool mInErrorState = false;
+    int mBufferQueueState = OK;
 
     bool isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const;
-    ANativeWindowBuffer* acquireFallbackBuffer();
+    ANativeWindowBuffer* acquireFallbackBuffer(int error);
     void clearReservedBuffer();
 
     void perform(int operation, va_list args);
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index c96e284..df7eeb3 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,8 +19,8 @@
 
 #include "RenderTask.h"
 
-#include "../JankTracker.h"
 #include "CacheManager.h"
+#include "ProfileDataContainer.h"
 #include "TimeLord.h"
 #include "WebViewFunctorManager.h"
 #include "thread/ThreadBase.h"
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index ec217c0..4c6a755 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -31,6 +31,7 @@
 #include "Frame.h"
 #include "IRenderPipeline.h"
 #include "VulkanSurface.h"
+#include "private/hwui/DrawVkInfo.h"
 
 class GrVkExtensions;
 
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
index bae616b..17ee17d 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.cpp
+++ b/libs/hwui/surfacetexture/ImageConsumer.cpp
@@ -71,13 +71,16 @@
     void makeImage(sp<GraphicBuffer>& graphicBuffer, android_dataspace dataspace,
                    GrContext* context);
 
+    void newBufferContent(GrContext* context);
+
 private:
     // The only way to invoke dtor is with unref, when mUsageCount is 0.
     ~AutoBackendTextureRelease() {}
 
     GrBackendTexture mBackendTexture;
     GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
-    GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+    GrAHardwareBufferUtils::UpdateImageProc mUpdateProc;
+    GrAHardwareBufferUtils::TexImageCtx mImageCtx;
 
     // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs
     // are held by SkImages.
@@ -101,7 +104,8 @@
         buffer->getWidth(),
         buffer->getHeight(),
         &mDeleteProc,
-        &mDeleteCtx,
+        &mUpdateProc,
+        &mImageCtx,
         createProtectedImage,
         backendFormat,
         false);
@@ -123,7 +127,7 @@
     mUsageCount--;
     if (mUsageCount <= 0) {
         if (mBackendTexture.isValid()) {
-            mDeleteProc(mDeleteCtx);
+            mDeleteProc(mImageCtx);
             mBackendTexture = {};
         }
         delete this;
@@ -154,6 +158,12 @@
     }
 }
 
+void AutoBackendTextureRelease::newBufferContent(GrContext* context) {
+    if (mBackendTexture.isValid()) {
+        mUpdateProc(mImageCtx, context);
+    }
+}
+
 void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer,
                                               android_dataspace dataspace, bool forceCreate,
                                               GrContext* context) {
@@ -166,6 +176,8 @@
 
         if (!mTextureRelease) {
             mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get());
+        } else {
+            mTextureRelease->newBufferContent(context);
         }
 
         mDataspace = dataspace;
diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h
index 2fdece9..3e2a91a 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.h
+++ b/libs/hwui/surfacetexture/ImageConsumer.h
@@ -26,11 +26,6 @@
 #include <gui/BufferItem.h>
 #include <system/graphics.h>
 
-namespace GrAHardwareBufferUtils {
-typedef void* DeleteImageCtx;
-typedef void (*DeleteImageProc)(DeleteImageCtx);
-}
-
 namespace android {
 
 namespace uirenderer {
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 400196b..c4067af 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <SkImagePriv.h>
+#include "hwui/Paint.h"
 #include "TestSceneBase.h"
 #include "tests/common/BitmapAllocationTestUtils.h"
 #include "utils/Color.h"
@@ -43,7 +44,7 @@
                     skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
                 });
 
-        SkPaint paint;
+        Paint paint;
         sk_sp<SkImage> image = hwuiBitmap->makeImage();
         sk_sp<SkShader> repeatShader =
                 image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat);
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 659926b..3d0a2b2 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -65,7 +65,7 @@
         sk_sp<SkShader> compositeShader(
                 SkShaders::Blend(SkBlendMode::kDstATop, hardwareShader, gradientShader));
 
-        SkPaint paint;
+        Paint paint;
         paint.setShader(std::move(compositeShader));
         canvas.drawRoundRect(0, 0, 400, 200, 10.0f, 10.0f, paint);
     }
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index c6b60aae..a9449b6 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -49,7 +49,7 @@
         SkMatrix matrix;
         matrix.setScale(1, length);
         matrix.postRotate(-90);
-        SkPaint fadingPaint;
+        Paint fadingPaint;
         fadingPaint.setShader(s->makeWithLocalMatrix(matrix));
         fadingPaint.setBlendMode(SkBlendMode::kDstOut);
         canvas.drawRect(0, 0, length, itemHeight, fadingPaint);
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index fb7e34d..d031923 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -79,7 +79,7 @@
         static sk_sp<Bitmap> filledBox(createBoxBitmap(true));
         static sk_sp<Bitmap> strokedBox(createBoxBitmap(false));
         // TODO: switch to using round rect clipping, once merging correctly handles that
-        SkPaint roundRectPaint;
+        Paint roundRectPaint;
         roundRectPaint.setAntiAlias(true);
         roundRectPaint.setColor(Color::White);
         canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
diff --git a/libs/hwui/tests/common/scenes/OvalAnimation.cpp b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
index 4ff868b..402c1ec 100644
--- a/libs/hwui/tests/common/scenes/OvalAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
@@ -28,7 +28,7 @@
     void createContent(int width, int height, Canvas& canvas) override {
         canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
         card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
-            SkPaint paint;
+            Paint paint;
             paint.setAntiAlias(true);
             paint.setColor(Color::Black);
             canvas.drawOval(0, 0, 200, 200, paint);
diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
index 6a3b6a5..d5ecfaf 100644
--- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
@@ -41,7 +41,7 @@
                 }
             }
 
-            SkPaint paint;
+            Paint paint;
             paint.setColor(0xff00ffff);
             canvas.drawRegion(region, paint);
         });
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 02dd42f..97bfba3 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -45,7 +45,7 @@
             canvas.save(SaveFlags::MatrixClip);
             canvas.translate(0, 400);
             canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::Flags(0));  // unclipped
-            SkPaint paint;
+            Paint paint;
             paint.setAntiAlias(true);
             paint.setColor(Color::Green_700);
             canvas.drawCircle(200, 200, 200, paint);
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index d189a93..70a1557 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -30,14 +30,14 @@
     void createContent(int width, int height, Canvas& canvas) override {
         card = TestUtils::createNode(
                 0, 0, width, height, [width](RenderProperties& props, Canvas& canvas) {
-                    std::function<void(Canvas&, float, const SkPaint&)> ops[] = {
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                    std::function<void(Canvas&, float, const Paint&)> ops[] = {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 canvas.drawArc(0, 0, size, size, 50, 189, true, paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 canvas.drawOval(0, 0, size, size, paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 SkPath diamondPath;
                                 diamondPath.moveTo(size / 2, 0);
                                 diamondPath.lineTo(size, size / 2);
@@ -46,18 +46,18 @@
                                 diamondPath.close();
                                 canvas.drawPath(diamondPath, paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 float data[] = {0, 0, size, size, 0, size, size, 0};
                                 canvas.drawLines(data, sizeof(data) / sizeof(float), paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 float data[] = {0, 0, size, size, 0, size, size, 0};
                                 canvas.drawPoints(data, sizeof(data) / sizeof(float), paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 canvas.drawRect(0, 0, size, size, paint);
                             },
-                            [](Canvas& canvas, float size, const SkPaint& paint) {
+                            [](Canvas& canvas, float size, const Paint& paint) {
                                 float rad = size / 4;
                                 canvas.drawRoundRect(0, 0, size, size, rad, rad, paint);
                             }};
@@ -66,7 +66,7 @@
 
                     // each combination of strokeWidth + style gets a column
                     int outerCount = canvas.save(SaveFlags::MatrixClip);
-                    SkPaint paint;
+                    Paint paint;
                     paint.setAntiAlias(true);
                     SkPaint::Style styles[] = {SkPaint::kStroke_Style, SkPaint::kFill_Style,
                                                SkPaint::kStrokeAndFill_Style};
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index e60bd5f..a0bc5aa 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -52,7 +52,7 @@
         return TestUtils::createNode(
                 x, y, x + width, y + height,
                 [width, height](RenderProperties& props, Canvas& canvas) {
-                    SkPaint paint;
+                    Paint paint;
                     // Simple scale/translate case where R, G, and B are all treated equivalently
                     SkColorMatrix cm;
                     cm.setScale(1.1f, 1.1f, 1.1f, 0.5f);
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 8bd804e..57a260c 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -51,7 +51,7 @@
                 [width, height](RenderProperties& props, Canvas& canvas) {
                     float pos[] = {0, 1};
                     SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
-                    SkPaint paint;
+                    Paint paint;
                     // overdraw several times to emphasize shader cost
                     for (int i = 0; i < 10; i++) {
                         // use i%2 start position to pick 2 color combo with black in it
diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h
index 6f76a50..24d3585 100644
--- a/libs/hwui/tests/common/scenes/TestSceneBase.h
+++ b/libs/hwui/tests/common/scenes/TestSceneBase.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "hwui/Canvas.h"
+#include "hwui/Paint.h"
 #include "RenderNode.h"
 #include "tests/common/TestContext.h"
 #include "tests/common/TestScene.h"
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index 76f0288..bac8870 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -217,7 +217,7 @@
             std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
                     image->stagingProperties().getWidth(), image->stagingProperties().getHeight(),
                     image.get()));
-            SkPaint paint;
+            Paint paint;
             sk_sp<SkColorFilter> filter(
                     SkColorFilters::Blend((curFrame % 150) << 24, SkBlendMode::kSrcATop));
             paint.setColorFilter(filter);
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 70423a7..4ce6c32 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -18,6 +18,7 @@
 
 #include "DisplayList.h"
 #include "hwui/Canvas.h"
+#include "hwui/Paint.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "tests/common/TestUtils.h"
 
@@ -93,7 +94,7 @@
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
     delete canvas->finishRecording();
 
-    SkPaint rectPaint;
+    Paint rectPaint;
     sk_sp<Bitmap> iconBitmap(TestUtils::createBitmap(80, 80));
 
     while (benchState.KeepRunning()) {
diff --git a/libs/hwui/tests/scripts/skp-capture.sh b/libs/hwui/tests/scripts/skp-capture.sh
index aad31fc..4b46fbf 100755
--- a/libs/hwui/tests/scripts/skp-capture.sh
+++ b/libs/hwui/tests/scripts/skp-capture.sh
@@ -29,10 +29,14 @@
 phase1_timeout_seconds=60
 phase2_timeout_seconds=300
 package="$1"
-filename="$(date '+%H%M%S').skp"
+extension="skp"
+if (( "$2" > 1 )); then # 2nd arg is number of frames
+    extension="mskp" # use different extension for multi frame files.
+fi
+filename="$(date '+%H%M%S').${extension}"
 remote_path="/data/data/${package}/cache/${filename}"
 local_path_prefix="$(date '+%Y-%m-%d_%H%M%S')_${package}"
-local_path="${local_path_prefix}.skp"
+local_path="${local_path_prefix}.${extension}"
 enable_capture_key='debug.hwui.capture_skp_enabled'
 enable_capture_value=$(adb shell "getprop '${enable_capture_key}'")
 
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index e70378b..3632be0 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -24,6 +24,7 @@
 #include "DamageAccumulator.h"
 #include "FatalTestCanvas.h"
 #include "IContextFactory.h"
+#include "hwui/Paint.h"
 #include "RecordingCanvas.h"
 #include "SkiaCanvas.h"
 #include "pipeline/skia/SkiaDisplayList.h"
@@ -59,7 +60,7 @@
 namespace {
 
 static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
-    SkPaint paint;
+    Paint paint;
     // order put in blue channel, transparent so overlapped content doesn't get rejected
     paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
     canvas->drawRect(0, 0, 100, 100, paint);
@@ -211,7 +212,7 @@
                 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
                 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
 
-                SkPaint paint;
+                Paint paint;
                 paint.setAntiAlias(true);
                 paint.setColor(SK_ColorGREEN);
                 recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
@@ -291,7 +292,7 @@
                 properties.setTranslationX(SCROLL_X);
                 properties.setTranslationY(SCROLL_Y);
 
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorWHITE);
                 canvas.drawRect(0, 0, 100, 100, paint);
             },
@@ -302,7 +303,7 @@
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 properties.setProjectBackwards(true);
                 properties.setClipToBounds(false);
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorDKGRAY);
                 canvas.drawRect(-10, -10, 60, 60, paint);
             },
@@ -310,7 +311,7 @@
     auto child = TestUtils::createSkiaNode(
             0, 50, 100, 100,
             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorBLUE);
                 canvas.drawRect(0, 0, 100, 50, paint);
                 canvas.drawRenderNode(projectingRipple.get());
@@ -375,14 +376,14 @@
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 properties.setProjectBackwards(true);
                 properties.setClipToBounds(false);
-                SkPaint paint;
+                Paint paint;
                 canvas.drawRect(0, 0, 100, 100, paint);
             },
             "P");
     auto child = TestUtils::createSkiaNode(
             0, 0, 100, 100,
             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
-                SkPaint paint;
+                Paint paint;
                 canvas.drawRect(0, 0, 100, 100, paint);
                 canvas.drawRenderNode(projectingRipple.get());
             },
@@ -483,7 +484,7 @@
                 properties.setTranslationX(SCROLL_X);
                 properties.setTranslationY(SCROLL_Y);
 
-                canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+                canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
             },
             "B");  // B
     auto projectingRipple = TestUtils::createSkiaNode(
@@ -491,14 +492,14 @@
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 properties.setProjectBackwards(true);
                 properties.setClipToBounds(false);
-                canvas.drawOval(100, 100, 300, 300, SkPaint());  // drawn mostly out of layer bounds
+                canvas.drawOval(100, 100, 300, 300, Paint());  // drawn mostly out of layer bounds
             },
             "R");  // R
     auto child = TestUtils::createSkiaNode(
             100, 100, 300, 300,
             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 canvas.drawRenderNode(projectingRipple.get());
-                canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
+                canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, Paint());
             },
             "C");  // C
     auto parent = TestUtils::createSkiaNode(
@@ -578,7 +579,7 @@
             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
                 properties.setProjectionReceiver(true);
-                canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+                canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
             },
             "B");  // B
     auto projectingRipple = TestUtils::createSkiaNode(
@@ -591,7 +592,7 @@
                 properties.setTranslationY(SCROLL_Y);
                 properties.setProjectBackwards(true);
                 properties.setClipToBounds(false);
-                canvas.drawOval(0, 0, 200, 200, SkPaint());
+                canvas.drawOval(0, 0, 200, 200, Paint());
             },
             "R");  // R
     auto child = TestUtils::createSkiaNode(
@@ -946,7 +947,7 @@
                                           [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
                                               sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
                                               canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
-                                                              SkPaint());
+                                                              Paint());
                                               canvas.drawBitmap(*bitmap, 10, 10, nullptr);
                                           });
 
@@ -1022,7 +1023,7 @@
 
     auto child = TestUtils::createSkiaNode(
             10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorWHITE);
                 canvas.drawRect(0, 0, 100, 100, paint);
             });
@@ -1030,7 +1031,7 @@
     auto parent = TestUtils::createSkiaNode(
             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
             [&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorDKGRAY);
                 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
 
@@ -1065,7 +1066,7 @@
     auto layerNode = TestUtils::createSkiaNode(
             0, 0, LAYER_WIDTH, LAYER_HEIGHT,
             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
-                canvas.drawPaint(SkPaint());
+                canvas.drawPaint(Paint());
             });
 
     layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 2ed1b25..fcc64fd 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -16,6 +16,7 @@
 
 #include "tests/common/TestUtils.h"
 
+#include <hwui/Paint.h>
 #include <SkBlurDrawLooper.h>
 #include <SkCanvasStateUtils.h>
 #include <SkPicture.h>
@@ -32,7 +33,7 @@
     // clear to white
     canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrc);
 
-    SkPaint paint;
+    Paint paint;
     // it is transparent to ensure that we still draw the rect since it has a looper
     paint.setColor(SK_ColorTRANSPARENT);
     // this is how view's shadow layers are implemented
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 7b76bd8..958baa7 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -23,6 +23,7 @@
 #include "AnimationContext.h"
 #include "DamageAccumulator.h"
 #include "IContextFactory.h"
+#include "hwui/Paint.h"
 #include "SkiaCanvas.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
@@ -96,7 +97,7 @@
 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
     auto halfGreenNode = TestUtils::createSkiaNode(
             0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
-                SkPaint greenPaint;
+                Paint greenPaint;
                 greenPaint.setColor(SK_ColorGREEN);
                 greenPaint.setStyle(SkPaint::kFill_Style);
                 bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
@@ -294,7 +295,7 @@
     };
 
     std::vector<sp<RenderNode>> nodes;
-    SkPaint transparentPaint;
+    Paint transparentPaint;
     transparentPaint.setAlpha(128);
 
     // backdrop
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 635429d..eec25c6 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -24,6 +24,7 @@
 #include "DamageAccumulator.h"
 #include "FatalTestCanvas.h"
 #include "IContextFactory.h"
+#include "hwui/Paint.h"
 #include "SkiaCanvas.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "pipeline/skia/SkiaPipeline.h"
@@ -60,7 +61,7 @@
             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
             [propSetupCallback](RenderProperties& props, SkiaRecordingCanvas& canvas) {
                 propSetupCallback(props);
-                SkPaint paint;
+                Paint paint;
                 paint.setColor(SK_ColorWHITE);
                 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
             });
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index ebf2343..e2fdf2f 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -67,29 +67,6 @@
         return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
     }
 
-    struct TextShadow {
-        SkScalar radius;
-        float dx;
-        float dy;
-        SkColor color;
-    };
-
-    static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) {
-        SkDrawLooper::BlurShadowRec blur;
-        if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) {
-            if (textShadow) {
-                textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma);
-                textShadow->dx = blur.fOffset.fX;
-                textShadow->dy = blur.fOffset.fY;
-                textShadow->color = blur.fColor;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    static inline bool hasTextShadow(const SkPaint* paint) { return getTextShadow(paint, nullptr); }
-
     static inline SkBlendMode getBlendModeDirect(const SkPaint* paint) {
         return paint ? paint->getBlendMode() : SkBlendMode::kSrcOver;
     }
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index a571630..8ae972b 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -29,10 +29,13 @@
  */
 interface ILocationProvider {
 
+    @UnsupportedAppUsage
     oneway void setLocationProviderManager(in ILocationProviderManager manager);
 
+    @UnsupportedAppUsage
     oneway void setRequest(in ProviderRequest request, in WorkSource ws);
 
+    @UnsupportedAppUsage
     oneway void sendExtraCommand(String command, in Bundle extras);
 
     // --- deprecated and will be removed the future ---
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 820d82d..65d3ffc 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -824,7 +824,7 @@
                 if (attributes != null) {
                     mUsage = attributes.mUsage;
                     mContentType = attributes.mContentType;
-                    mFlags = attributes.mFlags;
+                    mFlags = attributes.getAllFlags();
                     mMuteHapticChannels = attributes.areHapticChannelsMuted();
                     mTags = attributes.mTags;
                     mBundle = attributes.mBundle;
diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java
index 45e49a7..ac19bb1 100644
--- a/media/java/android/media/AudioPortConfig.java
+++ b/media/java/android/media/AudioPortConfig.java
@@ -95,7 +95,6 @@
 
     /**
      * The gain configuration if this port supports gain control, null otherwise
-     * @see AudioGainConfig.
      */
     public AudioGainConfig gain() {
         return mGain;
diff --git a/packages/DynamicSystemInstallationService/Android.bp b/packages/DynamicSystemInstallationService/Android.bp
new file mode 100644
index 0000000..f1a18ae
--- /dev/null
+++ b/packages/DynamicSystemInstallationService/Android.bp
@@ -0,0 +1,14 @@
+android_app {
+    name: "DynamicSystemInstallationService",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    certificate: "platform",
+    privileged: true,
+    platform_apis: true,
+
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/packages/DynamicSystemInstallationService/Android.mk b/packages/DynamicSystemInstallationService/Android.mk
deleted file mode 100644
index 16aca1b..0000000
--- a/packages/DynamicSystemInstallationService/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_PACKAGE_NAME := DynamicSystemInstallationService
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-
-include $(BUILD_PACKAGE)
diff --git a/packages/InputDevices/Android.bp b/packages/InputDevices/Android.bp
new file mode 100644
index 0000000..7532aea
--- /dev/null
+++ b/packages/InputDevices/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_app {
+    name: "InputDevices",
+
+    srcs: [
+        "**/*.java",
+        ":validate_input_devices_keymaps",
+    ],
+
+    resource_dirs: ["res"],
+
+    sdk_version: "current",
+    certificate: "platform",
+    privileged: true,
+}
+
+// Validate all key maps.
+// Produces an empty srcjar that is used as an input to InputDevices to make sure
+// the check runs for platform builds.
+genrule {
+    name: "validate_input_devices_keymaps",
+    tools: [
+        "validatekeymaps",
+        "soong_zip",
+    ],
+    srcs: ["res/raw/*.kcm"],
+    out: ["validate_input_devices_keymaps.srcjar"],
+    cmd: "$(location validatekeymaps) -q $(in) && $(location soong_zip) -o $(out)",
+}
diff --git a/packages/InputDevices/Android.mk b/packages/InputDevices/Android.mk
deleted file mode 100644
index 80803fd..0000000
--- a/packages/InputDevices/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES :=
-
-LOCAL_PACKAGE_NAME := InputDevices
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-include $(BUILD_PACKAGE)
-
-# Validate all key maps.
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := validate_input_devices_keymaps
-intermediates := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE),,COMMON)
-LOCAL_BUILT_MODULE := $(intermediates)/stamp
-
-validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
-input_devices_keymaps := $(wildcard $(LOCAL_PATH)/res/raw/*.kcm)
-$(LOCAL_BUILT_MODULE): PRIVATE_VALIDATEKEYMAPS := $(validatekeymaps)
-$(LOCAL_BUILT_MODULE) : $(input_devices_keymaps) | $(validatekeymaps)
-	$(hide) $(PRIVATE_VALIDATEKEYMAPS) -q $^
-	$(hide) mkdir -p $(dir $@) && touch $@
-
-# Run validatekeymaps unconditionally for platform build.
-droidcore : $(LOCAL_BUILT_MODULE)
-
-# Reset temp vars.
-validatekeymaps :=
-input_devices_keymaps :=
diff --git a/packages/MtpDocumentsProvider/Android.bp b/packages/MtpDocumentsProvider/Android.bp
new file mode 100644
index 0000000..3dafa26
--- /dev/null
+++ b/packages/MtpDocumentsProvider/Android.bp
@@ -0,0 +1,11 @@
+android_app {
+    name: "MtpDocumentsProvider",
+
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "media",
+    privileged: true,
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+    },
+}
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
deleted file mode 100644
index 2d62a07..0000000
--- a/packages/MtpDocumentsProvider/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := MtpDocumentsProvider
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := media
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-# Only enable asserts on userdebug/eng builds
-ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
-LOCAL_JACK_FLAGS += -D jack.assert.policy=always
-endif
-
-include $(BUILD_PACKAGE)
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/MtpDocumentsProvider/res/values-hi/strings.xml b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
index bbd0ae7..e469fc0 100644
--- a/packages/MtpDocumentsProvider/res/values-hi/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
@@ -19,7 +19,7 @@
     <string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
     <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
     <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> से फ़ाइलें एक्सेस कर रहा है"</string>
+    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> से फ़ाइलें ऐक्सेस कर रहा है"</string>
     <string name="error_busy_device" msgid="3997316850357386589">"दूसरा डिवाइस व्यस्त है. आप उसके उपलब्ध हो जाने तक फ़ाइलें ट्रांसफ़र नहीं कर सकते."</string>
     <string name="error_locked_device" msgid="7557872102188356147">"कोई फ़ाइल नहीं मिली. हो सकता है कि दूसरा डिवाइस लॉक हो. अगर ऐसा है, तो उसे अनलॉक करें और दोबारा कोशिश करें."</string>
 </resources>
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index b532621..7760e0e 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -23,6 +23,7 @@
         "SettingsLibBarChartPreference",
         "SettingsLibProgressBar",
         "SettingsLibAdaptiveIcon",
+        "SettingsLibRadioButtonPreference",
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index b56181d..b07176a 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -4,9 +4,10 @@
     srcs: ["src/**/*.java"],
     resource_dirs: ["res"],
 
-    libs: [
+    static_libs: [
         "androidx.annotation_annotation",
         "androidx.preference_preference",
+        "SettingsLibSettingsTheme",
     ],
     sdk_version: "system_current",
     min_sdk_version: "21",
diff --git a/packages/SettingsLib/EntityHeaderWidgets/Android.bp b/packages/SettingsLib/EntityHeaderWidgets/Android.bp
index 3ca4ecd..280848a 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/Android.bp
+++ b/packages/SettingsLib/EntityHeaderWidgets/Android.bp
@@ -6,7 +6,7 @@
 
     static_libs: [
           "androidx.annotation_annotation",
-          "SettingsLibAppPreference"
+          "SettingsLibSettingsTheme"
     ],
 
     sdk_version: "system_current",
diff --git a/packages/SettingsLib/RadioButtonPreference/Android.bp b/packages/SettingsLib/RadioButtonPreference/Android.bp
new file mode 100644
index 0000000..136d6da
--- /dev/null
+++ b/packages/SettingsLib/RadioButtonPreference/Android.bp
@@ -0,0 +1,14 @@
+android_library {
+    name: "SettingsLibRadioButtonPreference",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    static_libs: [
+          "androidx.preference_preference",
+          "SettingsLibSettingsTheme",
+    ],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml
similarity index 70%
copy from packages/SettingsLib/AppPreference/res/values/dimens.xml
copy to packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml
index e2a7a19..fda7fde 100644
--- a/packages/SettingsLib/AppPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2018 The Android Open Source Project
+  Copyright (C) 2019 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -13,8 +13,11 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-  -->
+-->
 
-<resources>
-    <dimen name="secondary_app_icon_size">32dp</dimen>
-</resources>
\ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
new file mode 100644
index 0000000..dcb014d
--- /dev/null
+++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:gravity="center_vertical"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+    <LinearLayout
+        android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:minWidth="56dp"
+        android:layout_marginEnd="16dp"
+        android:orientation="vertical"/>
+
+    <LinearLayout
+        android:id="@+id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:minWidth="32dp"
+        android:orientation="horizontal"
+        android:layout_marginEnd="16dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp">
+        <androidx.preference.internal.PreferenceImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            settings:maxWidth="@dimen/secondary_app_icon_size"
+            settings:maxHeight="@dimen/secondary_app_icon_size"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp">
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"/>
+
+        <LinearLayout
+            android:id="@+id/summary_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone">
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
+                android:textAlignment="viewStart"
+                android:textColor="?android:attr/textColorSecondary"/>
+
+            <TextView
+                android:id="@+id/appendix"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
+                android:textAlignment="viewEnd"
+                android:textColor="?android:attr/textColorSecondary"
+                android:maxLines="1"
+                android:ellipsize="end"/>
+        </LinearLayout>
+        <ProgressBar
+            android:id="@android:id/progress"
+            style="?android:attr/progressBarStyleHorizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:max="100"
+            android:visibility="gone"/>
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml
similarity index 60%
copy from packages/SettingsLib/AppPreference/res/values/dimens.xml
copy to packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml
index e2a7a19..cb7b8eb 100644
--- a/packages/SettingsLib/AppPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2018 The Android Open Source Project
+  Copyright (C) 2019 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -15,6 +15,11 @@
   limitations under the License.
   -->
 
-<resources>
-    <dimen name="secondary_app_icon_size">32dp</dimen>
-</resources>
\ No newline at end of file
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/checkbox"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:background="@null"
+    android:focusable="false"
+    android:clickable="false" />
diff --git a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
new file mode 100644
index 0000000..08287ac
--- /dev/null
+++ b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.core.content.res.TypedArrayUtils;
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * Check box preference with check box replaced by radio button.
+ *
+ * Functionally speaking, it's actually a CheckBoxPreference. We only modified
+ * the widget to RadioButton to make it "look like" a RadioButtonPreference.
+ *
+ * In other words, there's no "RadioButtonPreferenceGroup" in this
+ * implementation. When you check one RadioButtonPreference, if you want to
+ * uncheck all the other preferences, you should do that by code yourself.
+ */
+public class RadioButtonPreference extends CheckBoxPreference {
+
+    /**
+     * Interface definition for a callback to be invoked when the preference is clicked.
+     */
+    public interface OnClickListener {
+        /**
+         * Called when a preference has been clicked.
+         *
+         * @param emiter The clicked preference
+         */
+        void onRadioButtonClicked(RadioButtonPreference emiter);
+    }
+
+    private OnClickListener mListener = null;
+    private View mAppendix;
+    private int mAppendixVisibility = -1;
+
+
+    /**
+     * Perform inflation from XML and apply a class-specific base style.
+     *
+     * @param context      The {@link Context} this is associated with, through which it can
+     *                     access the current theme, resources, {@link SharedPreferences}, etc.
+     * @param attrs        The attributes of the XML tag that is inflating the preference
+     * @param defStyleAttr An attribute in the current theme that contains a reference to a style
+     *                     resource that supplies default values for the view. Can be 0 to not
+     *                     look for defaults.
+     */
+    public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
+        setLayoutResource(R.layout.preference_radio);
+        setIconSpaceReserved(false);
+    }
+
+
+    /**
+     * Perform inflation from XML and apply a class-specific base style.
+     *
+     * @param context      The {@link Context} this is associated with, through which it can
+     *                     access the current theme, resources, {@link SharedPreferences}, etc.
+     * @param attrs        The attributes of the XML tag that is inflating the preference
+     */
+    public RadioButtonPreference(Context context, AttributeSet attrs) {
+        this(context, attrs, TypedArrayUtils.getAttr(context,
+                androidx.preference.R.attr.preferenceStyle,
+                android.R.attr.preferenceStyle));
+    }
+
+    /**
+     * Constructor to create a preference.
+     *
+     * @param context The Context this is associated with.
+     */
+    public RadioButtonPreference(Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Sets the callback to be invoked when this preference is clicked by the user.
+     *
+     * @param listener The callback to be invoked
+     */
+    public void setOnClickListener(OnClickListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Processes a click on the preference.
+     */
+    @Override
+    public void onClick() {
+        if (mListener != null) {
+            mListener.onRadioButtonClicked(this);
+        }
+    }
+
+    /**
+     * Binds the created View to the data for this preference.
+     *
+     * <p>This is a good place to grab references to custom Views in the layout and set
+     * properties on them.
+     *
+     * <p>Make sure to call through to the superclass's implementation.
+     *
+     * @param holder The ViewHolder that provides references to the views to fill in. These views
+     *               will be recycled, so you should not hold a reference to them after this method
+     *               returns.
+     */
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        View summaryContainer = holder.findViewById(R.id.summary_container);
+        if (summaryContainer != null) {
+            summaryContainer.setVisibility(
+                    TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
+            mAppendix = holder.findViewById(R.id.appendix);
+            if (mAppendix != null && mAppendixVisibility != -1) {
+                mAppendix.setVisibility(mAppendixVisibility);
+            }
+        }
+
+        TextView title = (TextView) holder.findViewById(android.R.id.title);
+        if (title != null) {
+            title.setSingleLine(false);
+            title.setMaxLines(3);
+        }
+    }
+
+    /**
+     * Set the visibility state of appendix view.
+     *
+     * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
+     */
+    public void setAppendixVisibility(int visibility) {
+        if (mAppendix != null) {
+            mAppendix.setVisibility(visibility);
+        }
+        mAppendixVisibility = visibility;
+    }
+}
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
new file mode 100644
index 0000000..6d505bf
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -0,0 +1,8 @@
+android_library {
+    name: "SettingsLibSettingsTheme",
+
+    resource_dirs: ["res"],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/AndroidManifest.xml
similarity index 70%
copy from packages/SettingsLib/AppPreference/res/values/dimens.xml
copy to packages/SettingsLib/SettingsTheme/AndroidManifest.xml
index e2a7a19..fda7fde 100644
--- a/packages/SettingsLib/AppPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2018 The Android Open Source Project
+  Copyright (C) 2019 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -13,8 +13,11 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-  -->
+-->
 
-<resources>
-    <dimen name="secondary_app_icon_size">32dp</dimen>
-</resources>
\ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
similarity index 92%
rename from packages/SettingsLib/AppPreference/res/values/dimens.xml
rename to packages/SettingsLib/SettingsTheme/res/values/dimens.xml
index e2a7a19..9485655 100644
--- a/packages/SettingsLib/AppPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2018 The Android Open Source Project
+  Copyright (C) 2019 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -17,4 +17,4 @@
 
 <resources>
     <dimen name="secondary_app_icon_size">32dp</dimen>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index beb1ac5..2734f4e 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -141,7 +141,7 @@
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicaciones eliminadas"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicaciones y usuarios eliminados"</string>
     <string name="data_usage_ota" msgid="5377889154805560860">"Actualizaciones del sistema"</string>
-    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Conexión USB"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Conexión a red por USB"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portátil"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Conexión Bluetooth"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Compartir conexión"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 238eba5..3a20d04 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -46,7 +46,7 @@
     <string name="wifi_limited_connection" msgid="7717855024753201527">"सीमित कनेक्शन"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"इंटरनेट कनेक्शन नहीं है"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन करना ज़रूरी है"</string>
-    <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"एक्सेस पॉइंट फ़िलहाल भरा हुआ है"</string>
+    <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ऐक्सेस पॉइंट फ़िलहाल भरा हुआ है"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s के ज़रिए कनेक्ट"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s के ज़रिए उपलब्ध"</string>
     <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> खोला जा रहा है"</string>
@@ -68,7 +68,7 @@
     <string name="bluetooth_pairing" msgid="1426882272690346242">"युग्‍मित कर रहा है…"</string>
     <string name="bluetooth_connected_no_headset" msgid="616068069034994802">"जुड़ गया (फ़ोन के ऑडियो को छोड़कर)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"जुड़ गया (मीडिया ऑडियो को छोड़कर)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"जुड़ गया (मैसेज का एक्सेस नहीं)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"जुड़ गया (मैसेज का ऐक्सेस नहीं)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"जुड़ गया (फ़ोन या मीडिया ऑडियो को छोड़कर)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"जुड़ गया, बैटरी का लेवल <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"जुड़ गया (फ़ोन के ऑडियो को छोड़कर), बैटरी का लेवल <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
@@ -88,7 +88,7 @@
     <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"संपर्क साझाकरण के लिए उपयोग करें"</string>
     <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"इंटरनेट कनेक्शन साझाकरण"</string>
     <string name="bluetooth_profile_map" msgid="1019763341565580450">"लेख संदेश"</string>
-    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम एक्सेस"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम ऐक्सेस"</string>
     <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ऑडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
     <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ऑडियो"</string>
     <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"सुनने में मदद करने वाले डिवाइस"</string>
@@ -200,7 +200,7 @@
     <string name="development_settings_not_available" msgid="4308569041701535607">"यह उपयोगकर्ता, डेवलपर के लिए सेटिंग और टूल का इस्तेमाल नहीं कर सकता"</string>
     <string name="vpn_settings_not_available" msgid="956841430176985598">"VPN सेटिंग इस उपयोगकर्ता के लिए उपलब्ध नहीं हैं"</string>
     <string name="tethering_settings_not_available" msgid="6765770438438291012">"टेदरिंग सेटिंग इस उपयोगकर्ता के लिए उपलब्ध नहीं हैं"</string>
-    <string name="apn_settings_not_available" msgid="7873729032165324000">"एक्सेस पॉइंट के नाम की सेटिंग इस उपयोगकर्ता के लिए मौजूद नहीं हैं"</string>
+    <string name="apn_settings_not_available" msgid="7873729032165324000">"ऐक्सेस पॉइंट के नाम की सेटिंग इस उपयोगकर्ता के लिए मौजूद नहीं हैं"</string>
     <string name="enable_adb" msgid="7982306934419797485">"USB डीबग करना"</string>
     <string name="enable_adb_summary" msgid="4881186971746056635">"डीबग मोड जब USB कनेक्‍ट किया गया हो"</string>
     <string name="clear_adb_keys" msgid="4038889221503122743">"USB डीबग करने की मंज़ूरी रद्द करें"</string>
@@ -414,7 +414,7 @@
     <string name="disabled" msgid="9206776641295849915">"बंद किया गया"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"अनुमति है"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"अनुमति नहीं है"</string>
-    <string name="install_other_apps" msgid="6986686991775883017">"अनजान ऐप्लिकेशन इंस्टॉल करने का एक्सेस"</string>
+    <string name="install_other_apps" msgid="6986686991775883017">"अनजान ऐप्लिकेशन इंस्टॉल करने का ऐक्सेस"</string>
     <string name="home" msgid="3256884684164448244">"सेटिंग का होम पेज"</string>
   <string-array name="battery_labels">
     <item msgid="8494684293649631252">"0%"</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 59754e0..81d1ea5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1434,7 +1434,7 @@
 
     void update(@Nullable WifiConfiguration config) {
         mConfig = config;
-        if (mConfig != null) {
+        if (mConfig != null && !isPasspoint()) {
             ssid = removeDoubleQuotes(mConfig.SSID);
         }
         networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID;
diff --git a/packages/SettingsLib/tests/Android.mk b/packages/SettingsLib/tests/Android.mk
deleted file mode 100644
index 333c41d..0000000
--- a/packages/SettingsLib/tests/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# Include all makefiles in subdirectories
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
new file mode 100644
index 0000000..d58e68a
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class RadioButtonPreferenceTest {
+
+    private Application mContext;
+    private RadioButtonPreference mPreference;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mPreference = new RadioButtonPreference(mContext);
+    }
+
+    @Test
+    public void shouldHaveRadioPreferenceLayout() {
+        assertThat(mPreference.getLayoutResource()).isEqualTo(R.layout.preference_radio);
+    }
+
+    @Test
+    public void iconSpaceReservedShouldBeFalse() {
+        assertThat(mPreference.isIconSpaceReserved()).isFalse();
+    }
+
+    @Test
+    public void summary_containerShouldBeVisible() {
+        mPreference.setSummary("some summary");
+        View summaryContainer = new View(mContext);
+        View view = mock(View.class);
+        when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+        PreferenceViewHolder preferenceViewHolder =
+                PreferenceViewHolder.createInstanceForTests(view);
+        mPreference.onBindViewHolder(preferenceViewHolder);
+        assertEquals(View.VISIBLE, summaryContainer.getVisibility());
+    }
+
+    @Test
+    public void emptySummary_containerShouldBeGone() {
+        mPreference.setSummary("");
+        View summaryContainer = new View(mContext);
+        View view = mock(View.class);
+        when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+        PreferenceViewHolder preferenceViewHolder =
+                PreferenceViewHolder.createInstanceForTests(view);
+        mPreference.onBindViewHolder(preferenceViewHolder);
+        assertEquals(View.GONE, summaryContainer.getVisibility());
+    }
+
+    @Test
+    public void nullSummary_containerShouldBeGone() {
+        mPreference.setSummary(null);
+        View summaryContainer = new View(mContext);
+        View view = mock(View.class);
+        when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+        PreferenceViewHolder preferenceViewHolder =
+                PreferenceViewHolder.createInstanceForTests(view);
+        mPreference.onBindViewHolder(preferenceViewHolder);
+        assertEquals(View.GONE, summaryContainer.getVisibility());
+    }
+
+    @Test
+    public void hideAppendix_shouldBeGone() {
+        mPreference.setAppendixVisibility(View.GONE);
+        View view = LayoutInflater.from(mContext).inflate(R.layout.preference_radio, null);
+        PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
+        mPreference.onBindViewHolder(holder);
+        assertThat(holder.findViewById(R.id.appendix).getVisibility()).isEqualTo(View.GONE);
+    }
+}
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 36bdf23..2727880 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -366,8 +366,10 @@
             checkProgressUpdated(mInfo, (int) progress);
         }
 
-        // TODO(b/127431371): Add error code handling for bugreport API errors.
-        // Logging errors and removing progress notification for now.
+        /**
+         * Logs errors and stops the service on which this bugreport was running.
+         * Also stops progress notification (if any).
+         */
         @Override
         public void onError(@BugreportErrorCode int errorCode) {
             trackInfoWithId();
@@ -557,12 +559,17 @@
         }
     }
 
+    private String getBugreportName() {
+        String buildId = SystemProperties.get("ro.build.id", "UNKNOWN_BUILD");
+        String deviceName = SystemProperties.get("ro.product.name", "UNKNOWN_DEVICE");
+        String currentTimestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
+        return String.format("bugreport-%s-%s-%s", deviceName, buildId, currentTimestamp);
+    }
+
     private void startBugreportAPI(Intent intent) {
         mUsingBugreportApi = true;
-        String bugreportName = "bugreport-" + new SimpleDateFormat("yyyy-MM-dd-HH-mm").format(
-                new Date());
+        String bugreportName = getBugreportName();
 
-        // TODO(b/126862297): Make file naming same as dumpstate triggered bugreports
         ParcelFileDescriptor bugreportFd = createReadWriteFile(BUGREPORT_DIR,
                 bugreportName + ".zip");
         if (bugreportFd == null) {
diff --git a/packages/SimAppDialog/Android.bp b/packages/SimAppDialog/Android.bp
new file mode 100644
index 0000000..ff26710
--- /dev/null
+++ b/packages/SimAppDialog/Android.bp
@@ -0,0 +1,15 @@
+android_app {
+    name: "SimAppDialog",
+
+    srcs: ["src/**/*.java"],
+
+    platform_apis: true,
+    certificate: "platform",
+
+    static_libs: [
+        "androidx.legacy_legacy-support-v4",
+        "setup-wizard-lib",
+    ],
+
+    resource_dirs: ["res"],
+}
diff --git a/packages/SimAppDialog/Android.mk b/packages/SimAppDialog/Android.mk
deleted file mode 100644
index 991e333..0000000
--- a/packages/SimAppDialog/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := SimAppDialog
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    androidx.legacy_legacy-support-v4
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-include frameworks/opt/setupwizard/library/common-platform-deprecated.mk
-
-include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 4fae3c5..76c1045 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -42,6 +42,32 @@
         android:visibility="gone"
         />
 
+    <LinearLayout
+        android:id="@+id/divider_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:background="@color/transparent" >
+
+        <android.widget.Space
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:layout_weight="@integer/qqs_split_fraction" />
+
+        <com.android.systemui.DarkReceiverImpl
+            android:id="@+id/divider"
+            android:layout_height="match_parent"
+            android:layout_width="1dp"
+            android:layout_marginTop="4dp"
+            android:layout_marginBottom="4dp" />
+
+        <android.widget.Space
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:layout_weight="@integer/qs_split_fraction" />
+
+    </LinearLayout>
+
     <LinearLayout android:id="@+id/status_bar_contents"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 861187f..340cb3a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -482,4 +482,7 @@
      -->
     <string name="config_rounded_mask" translatable="false">"M8,0C3.6,0,0,3.6,0,8"</string>
 
+    <!-- Preferred refresh rate at keyguard, if supported by the display -->
+    <integer name="config_keyguardRefreshRate">-1</integer>
+
 </resources>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index a6dae45..deae7e2 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -27,4 +27,9 @@
          performance issues arise. -->
     <integer name="bubbles_max_rendered">5</integer>
 
+    <!-- Ratio of "left" end of status bar that will swipe to QQS. -->
+    <integer name="qqs_split_fraction">3</integer>
+    <!-- Ratio of "right" end of status bar that will swipe to QS. -->
+    <integer name="qs_split_fraction">2</integer>
+
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 328116d..13fc702 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -236,7 +236,8 @@
 
                     @Override
                     public void onAnimationCanceled(boolean deferredWithScreenshot) {
-                        animationHandler.onAnimationCanceled(deferredWithScreenshot);
+                        animationHandler.onAnimationCanceled(
+                                deferredWithScreenshot ? new ThumbnailData() : null);
                     }
                 };
             }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index 5850fda..579858a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -18,6 +18,8 @@
 
 import android.graphics.Rect;
 
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
 public interface RecentsAnimationListener {
 
     /**
@@ -29,5 +31,5 @@
     /**
      * Called when the animation into Recents was canceled. This call is made on the binder thread.
      */
-    void onAnimationCanceled(boolean deferredWithScreenshot);
+    void onAnimationCanceled(ThumbnailData thumbnailData);
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 11d093f..10d132a 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -400,8 +400,11 @@
             }
         }
 
+        if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames);
+
         displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot,
                 allSimsMissing);
+
         boolean airplaneMode = false;
         // APM (airplane mode) != no carrier state. There are carrier services
         // (e.g. WFC = Wi-Fi calling) which may operate in APM.
@@ -410,9 +413,6 @@
             airplaneMode = true;
         }
 
-        if (TextUtils.isEmpty(displayText) && !airplaneMode) {
-            displayText = joinNotEmpty(mSeparator, carrierNames);
-        }
         final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
                 displayText,
                 carrierNames,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index fb3a586..69da990 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -123,7 +123,7 @@
             msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
         }
 
-        if (mSecurityMessageDisplay != null) {
+        if (mSecurityMessageDisplay != null && getVisibility() == VISIBLE) {
             mSecurityMessageDisplay.setMessage(msg);
         }
         mSimImageView.setImageTintList(ColorStateList.valueOf(color));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 4e7b157..76bed23 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -182,6 +182,11 @@
     public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2;
 
     private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
+    /**
+     * If no cancel signal has been received after this amount of time, set the biometric running
+     * state to stopped to allow Keyguard to retry authentication.
+     */
+    private static final int DEFAULT_CANCEL_SIGNAL_TIMEOUT = 3000;
 
     private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
             "com.android.settings", "com.android.settings.FallbackHome");
@@ -264,11 +269,20 @@
      */
     private static final int BIOMETRIC_CONTINUE_DELAY_MS = 500;
 
-    // If FP daemon dies, keyguard should retry after a short delay
+    // If the HAL dies or is unable to authenticate, keyguard should retry after a short delay
     private int mHardwareFingerprintUnavailableRetryCount = 0;
     private int mHardwareFaceUnavailableRetryCount = 0;
-    private static final int HW_UNAVAILABLE_TIMEOUT = 3000; // ms
-    private static final int HW_UNAVAILABLE_RETRY_MAX = 3;
+    private static final int HAL_ERROR_RETRY_TIMEOUT = 500; // ms
+    private static final int HAL_ERROR_RETRY_MAX = 10;
+
+    private final Runnable mCancelNotReceived = new Runnable() {
+        @Override
+        public void run() {
+            Log.w(TAG, "Cancel not received, transitioning to STOPPED");
+            mFingerprintRunningState = mFaceRunningState = BIOMETRIC_STATE_STOPPED;
+            updateBiometricListeningState();
+        }
+    };
 
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
@@ -662,6 +676,11 @@
     };
 
     private void handleFingerprintError(int msgId, String errString) {
+        if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED && mHandler.hasCallbacks(
+                mCancelNotReceived)) {
+            mHandler.removeCallbacks(mCancelNotReceived);
+        }
+
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
                 && mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
@@ -671,10 +690,10 @@
         }
 
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
-            if (mHardwareFingerprintUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) {
+            if (mHardwareFingerprintUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
                 mHardwareFingerprintUnavailableRetryCount++;
                 mHandler.removeCallbacks(mRetryFingerprintAuthentication);
-                mHandler.postDelayed(mRetryFingerprintAuthentication, HW_UNAVAILABLE_TIMEOUT);
+                mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT);
             }
         }
 
@@ -822,6 +841,10 @@
 
     private void handleFaceError(int msgId, String errString) {
         if (DEBUG_FACE) Log.d(TAG, "Face error received: " + errString);
+        if (msgId == FaceManager.FACE_ERROR_CANCELED && mHandler.hasCallbacks(mCancelNotReceived)) {
+            mHandler.removeCallbacks(mCancelNotReceived);
+        }
+
         if (msgId == FaceManager.FACE_ERROR_CANCELED
                 && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
@@ -830,11 +853,12 @@
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         }
 
-        if (msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE) {
-            if (mHardwareFaceUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) {
+        if (msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE
+                || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
+            if (mHardwareFaceUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
                 mHardwareFaceUnavailableRetryCount++;
                 mHandler.removeCallbacks(mRetryFaceAuthentication);
-                mHandler.postDelayed(mRetryFaceAuthentication, HW_UNAVAILABLE_TIMEOUT);
+                mHandler.postDelayed(mRetryFaceAuthentication, HAL_ERROR_RETRY_TIMEOUT);
             }
         }
 
@@ -1802,6 +1826,9 @@
             if (mFingerprintCancelSignal != null) {
                 mFingerprintCancelSignal.cancel();
                 mFingerprintCancelSignal = null;
+                if (!mHandler.hasCallbacks(mCancelNotReceived)) {
+                    mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
+                }
             }
             setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING);
         }
@@ -1816,6 +1843,9 @@
             if (mFaceCancelSignal != null) {
                 mFaceCancelSignal.cancel();
                 mFaceCancelSignal = null;
+                if (!mHandler.hasCallbacks(mCancelNotReceived)) {
+                    mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
+                }
             }
             setFaceRunningState(BIOMETRIC_STATE_CANCELLING);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
index 54a3635..a94952c 100644
--- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
@@ -107,7 +107,9 @@
         mPaint.setColor((int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
                 mLightColor,
                 mDarkColor));
-        invalidate();
+        if (getVisibility() == VISIBLE) {
+            invalidate();
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt b/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt
new file mode 100644
index 0000000..42d38cb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui
+
+import android.content.Context
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.view.View
+import com.android.systemui.plugins.DarkIconDispatcher
+
+class DarkReceiverImpl @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyle: Int = 0,
+    defStyleRes: Int = 0
+) : View(context, attrs, defStyle, defStyleRes), DarkIconDispatcher.DarkReceiver {
+
+    private val dualToneHandler = DualToneHandler(context)
+
+    init {
+        onDarkChanged(Rect(), 1f, DarkIconDispatcher.DEFAULT_ICON_TINT)
+    }
+
+    override fun onDarkChanged(area: Rect?, darkIntensity: Float, tint: Int) {
+        val intensity = if (DarkIconDispatcher.isInArea(area, this)) darkIntensity else 0f
+        setBackgroundColor(dualToneHandler.getSingleColor(intensity))
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/DumpController.kt b/packages/SystemUI/src/com/android/systemui/DumpController.kt
index 646abb5..65f1abd 100644
--- a/packages/SystemUI/src/com/android/systemui/DumpController.kt
+++ b/packages/SystemUI/src/com/android/systemui/DumpController.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui
 
+import android.util.ArraySet
 import android.util.Log
 import androidx.annotation.GuardedBy
 import com.android.internal.util.Preconditions
@@ -39,38 +40,39 @@
     }
 
     @GuardedBy("listeners")
-    private val listeners = mutableListOf<WeakReference<Dumpable>>()
+    private val listeners = mutableListOf<RegisteredDumpable>()
     val numListeners: Int
         get() = listeners.size
 
     /**
-     * Adds a [Dumpable] listener to be dumped. It will only be added if it is not already tracked.
+     * Adds a [Dumpable] dumpable to be dumped.
      *
-     * @param listener the [Dumpable] to be added
+     * @param tag a string tag to associate with this dumpable. Tags must be globally unique; this
+     *      method will throw if the same tag has already been registered. Tags can be used to
+     *      filter output when debugging.
+     * @param dumpable the [Dumpable] to be added
      */
-    fun addListener(listener: Dumpable) {
-        Preconditions.checkNotNull(listener, "The listener to be added cannot be null")
-        if (DEBUG) Log.v(TAG, "*** register callback for $listener")
+    fun registerDumpable(tag: String, dumpable: Dumpable) {
+        Preconditions.checkNotNull(dumpable, "The dumpable to be added cannot be null")
+        if (DEBUG) Log.v(TAG, "*** register callback for $dumpable")
         synchronized<Unit>(listeners) {
-            if (listeners.any { it.get() == listener }) {
-                if (DEBUG) {
-                    Log.e(TAG, "Object tried to add another callback")
-                }
+            if (listeners.any { it.tag == tag }) {
+                throw IllegalArgumentException("Duplicate dumpable tag registered: $tag")
             } else {
-                listeners.add(WeakReference(listener))
+                listeners.add(RegisteredDumpable(tag, WeakReference(dumpable)))
             }
         }
     }
 
     /**
-     * Removes a listener from the list of elements to be dumped.
+     * Removes a dumpable from the list of elements to be dumped.
      *
-     * @param listener the [Dumpable] to be removed.
+     * @param dumpable the [Dumpable] to be removed.
      */
-    fun removeListener(listener: Dumpable) {
-        if (DEBUG) Log.v(TAG, "*** unregister callback for $listener")
+    fun unregisterDumpable(dumpable: Dumpable) {
+        if (DEBUG) Log.v(TAG, "*** unregister callback for $dumpable")
         synchronized(listeners) {
-            listeners.removeAll { it.get() == listener || it.get() == null }
+            listeners.removeAll { it.dumpable.get() == dumpable || it.dumpable.get() == null }
         }
     }
 
@@ -79,8 +81,22 @@
      */
     override fun dump(fd: FileDescriptor?, pw: PrintWriter, args: Array<String>?) {
         pw.println("DumpController state:")
+
+        val filter = if (args != null && args.size >= 3 &&
+                args[0] == "dependency" && args[1] == "DumpController") {
+            ArraySet(args[2].split(',').map { it.toLowerCase() })
+        } else {
+            null
+        }
+
         synchronized(listeners) {
-            listeners.forEach { it.get()?.dump(fd, pw, args) }
+            listeners.forEach {
+                if (filter == null || filter.contains(it.tag.toLowerCase())) {
+                    it.dumpable.get()?.dump(fd, pw, args)
+                }
+            }
         }
     }
+
+    data class RegisteredDumpable(val tag: String, val dumpable: WeakReference<Dumpable>)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
index 002d4f3..0cee030 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
@@ -74,6 +74,7 @@
 
     private boolean mHandlesShowing = false;
     private long mHandlesLastHiddenAt;
+    private long mShowAndGoEndsAt;
     /**
      * This should always be initialized as {@link AssistHandleBehavior#OFF} to ensure proper
      * behavior lifecycle.
@@ -127,7 +128,7 @@
                                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE, null));
                     }
                 });
-        Dependency.get(DumpController.class).addListener(this);
+        Dependency.get(DumpController.class).registerDumpable(TAG, this);
     }
 
     @Override // AssistHandleCallbacks
@@ -144,7 +145,9 @@
 
     private void showAndGoInternal() {
         maybeShowHandles(/* ignoreThreshold = */ false);
-        mHandler.postDelayed(mHideHandles, getShowAndGoDuration());
+        long showAndGoDuration = getShowAndGoDuration();
+        mShowAndGoEndsAt = SystemClock.elapsedRealtime() + showAndGoDuration;
+        mHandler.postDelayed(mHideHandles, showAndGoDuration);
     }
 
     @Override // AssistHandleCallbacks
@@ -162,6 +165,10 @@
         mHandler.post(() -> maybeShowHandles(/* ignoreThreshold = */ true));
     }
 
+    public long getShowAndGoRemainingTimeMs() {
+        return Long.max(mShowAndGoEndsAt - SystemClock.elapsedRealtime(), 0);
+    }
+
     boolean areHandlesShowing() {
         return mHandlesShowing;
     }
@@ -271,6 +278,7 @@
     private void clearPendingCommands() {
         mHandler.removeCallbacks(mHideHandles);
         mHandler.removeCallbacks(mShowAndGo);
+        mShowAndGoEndsAt = 0;
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 97b6e7c..4a4fead 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -82,7 +82,7 @@
         void processBundle(Bundle hints);
 
         /**
-         * Hides the UI.
+         * Hides any SysUI for the assistant, but _does not_ close the assistant itself.
          */
         void hide();
     }
@@ -440,6 +440,10 @@
         mAssistUtils.onLockscreenShown();
     }
 
+    public long getAssistHandleShowAndGoRemainingDurationMs() {
+        return mHandleController.getShowAndGoRemainingTimeMs();
+    }
+
     /** Returns the logging flags for the given Assistant invocation type. */
     public int toLoggingSubType(int invocationType) {
         return toLoggingSubType(invocationType, mPhoneStateMonitor.getPhoneState());
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index 662de3a..0c4f051 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -118,7 +118,6 @@
 
     @Override // AssistManager.UiController
     public void hide() {
-        Dependency.get(AssistManager.class).hideAssist();
         detach();
         if (mInvocationAnimator.isRunning()) {
             mInvocationAnimator.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 9bca3c7..c09e284 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -261,6 +261,12 @@
                 + state + " blocked=" + blocked);
     }
 
+    public static void tracePulseDropped(Context context, String why) {
+        if (!ENABLED) return;
+        init(context);
+        log("pulseDropped why=" + why);
+    }
+
     public static void tracePulseTouchDisabledByProx(Context context, boolean disabled) {
         if (!ENABLED) return;
         init(context);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 2ca85c0..310f04a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -113,11 +113,13 @@
         if (!sWakeDisplaySensorState) {
             Log.d(TAG, "Wake display false. Pulse denied.");
             runIfNotNull(onPulseSuppressedListener);
+            DozeLog.tracePulseDropped(mContext, "wakeDisplaySensor");
             return;
         }
         mNotificationPulseTime = SystemClock.elapsedRealtime();
         if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
             runIfNotNull(onPulseSuppressedListener);
+            DozeLog.tracePulseDropped(mContext, "pulseOnNotificationsDisabled");
             return;
         }
         requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,
@@ -376,6 +378,7 @@
         proximityCheckThenCall((result) -> {
             if (result == ProximityCheck.RESULT_NEAR) {
                 // in pocket, abort pulse
+                DozeLog.tracePulseDropped(mContext, "inPocket");
                 mPulsePending = false;
                 runIfNotNull(onPulseSuppressedListener);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index df3f36e..3f598ff 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -95,6 +95,7 @@
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.phone.UnlockMethodCache;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.EmergencyDialerConstants;
@@ -1523,6 +1524,8 @@
         private boolean mShowing;
         private float mScrimAlpha;
         private ResetOrientationData mResetOrientationData;
+        private boolean mHadTopUi;
+        private final StatusBarWindowController mStatusBarWindowController;
 
         ActionsDialog(Context context, MyAdapter adapter,
                 GlobalActionsPanelPlugin.PanelViewController plugin) {
@@ -1531,6 +1534,7 @@
             mAdapter = adapter;
             mColorExtractor = Dependency.get(SysuiColorExtractor.class);
             mStatusBarService = Dependency.get(IStatusBarService.class);
+            mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
 
             // Window initialization
             Window window = getWindow();
@@ -1706,6 +1710,8 @@
         public void show() {
             super.show();
             mShowing = true;
+            mHadTopUi = mStatusBarWindowController.getForceHasTopUi();
+            mStatusBarWindowController.setForceHasTopUi(true);
             mBackgroundDrawable.setAlpha(0);
             mGlobalActionsLayout.setTranslationX(mGlobalActionsLayout.getAnimationOffsetX());
             mGlobalActionsLayout.setTranslationY(mGlobalActionsLayout.getAnimationOffsetY());
@@ -1738,7 +1744,7 @@
                     .translationX(mGlobalActionsLayout.getAnimationOffsetX())
                     .translationY(mGlobalActionsLayout.getAnimationOffsetY())
                     .setDuration(300)
-                    .withEndAction(super::dismiss)
+                    .withEndAction(this::completeDismiss)
                     .setInterpolator(new LogAccelerateInterpolator())
                     .setUpdateListener(animation -> {
                         int alpha = (int) ((1f - (Float) animation.getAnimatedValue())
@@ -1751,10 +1757,15 @@
         }
 
         void dismissImmediately() {
-            super.dismiss();
             mShowing = false;
             dismissPanel();
             resetOrientation();
+            completeDismiss();
+        }
+
+        private void completeDismiss() {
+            mStatusBarWindowController.setForceHasTopUi(mHadTopUi);
+            super.dismiss();
         }
 
         private void dismissPanel() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6b2721a..36c3cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -90,6 +90,7 @@
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.util.InjectionInflationController;
 
 import java.io.FileDescriptor;
@@ -204,6 +205,8 @@
     private AlarmManager mAlarmManager;
     private AudioManager mAudioManager;
     private StatusBarManager mStatusBarManager;
+    private final StatusBarWindowController mStatusBarWindowController =
+            Dependency.get(StatusBarWindowController.class);
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
 
     private boolean mSystemReady;
@@ -1779,6 +1782,7 @@
             adjustStatusBarLocked();
             userActivity();
             mUpdateMonitor.setKeyguardGoingAway(false /* away */);
+            mStatusBarWindowController.setKeyguardGoingAway(false /* goingAway */);
             mShowKeyguardWakeLock.release();
         }
         mKeyguardDisplayManager.show();
@@ -1811,6 +1815,7 @@
             }
 
             mUpdateMonitor.setKeyguardGoingAway(true /* goingAway */);
+            mStatusBarWindowController.setKeyguardGoingAway(true /* goingAway */);
 
             // Don't actually hide the Keyguard at the moment, wait for window
             // manager until it tells us it's safe to do so with
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 89aa96d..ae83567 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -187,7 +187,7 @@
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.addCallback(this);
         }
-        if (mDumpController != null) mDumpController.addListener(this);
+        if (mDumpController != null) mDumpController.registerDumpable(getDumpableTag(), this);
     }
 
     @Override
@@ -202,10 +202,14 @@
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.removeCallback(this);
         }
-        if (mDumpController != null) mDumpController.removeListener(this);
+        if (mDumpController != null) mDumpController.unregisterDumpable(this);
         super.onDetachedFromWindow();
     }
 
+    protected String getDumpableTag() {
+        return TAG;
+    }
+
     @Override
     public void onTilesChanged() {
         setTiles(mHost.getTiles());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index fed59a5..b27bf32 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -109,7 +109,7 @@
         defaultFactory.setHost(this);
         mQsFactories.add(defaultFactory);
         pluginManager.addPluginListener(this, QSFactory.class, true);
-        mDumpController.addListener(this);
+        mDumpController.registerDumpable(TAG, this);
 
         mainHandler.post(() -> {
             // This is technically a hack to avoid circular dependency of
@@ -131,7 +131,7 @@
         mTunerService.removeTunable(this);
         mServices.destroy();
         mPluginManager.removePluginListener(this);
-        mDumpController.removeListener(this);
+        mDumpController.unregisterDumpable(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 73f6fc5..f1e9c87 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -96,6 +96,11 @@
         Dependency.get(TunerService.class).removeTunable(mNumTiles);
     }
 
+    @Override
+    protected String getDumpableTag() {
+        return TAG;
+    }
+
     public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
         mFullPanel = fullPanel;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 20069ea..4de42cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -40,8 +40,10 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
+import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SignalTileView;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.NetworkController;
@@ -78,6 +80,11 @@
     }
 
     @Override
+    public QSIconView createTileView(Context context) {
+        return new SignalTileView(context);
+    }
+
+    @Override
     public DetailAdapter getDetailAdapter() {
         return mDetailAdapter;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 19edc94..16f0b15 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -546,7 +546,8 @@
             navBarFragment.updateSystemUiStateFlags(-1);
         }
         if (navBarView != null) {
-            navBarView.updateSystemUiStateFlags();
+            navBarView.updatePanelSystemUiStateFlags();
+            navBarView.updateDisabledSystemUiStateFlags();
         }
         if (mStatusBarWinController != null) {
             mStatusBarWinController.notifyStateChangedCallbacks();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 6329af5..fa0fe13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -43,7 +43,6 @@
 import android.os.Message;
 import android.util.Pair;
 import android.util.SparseArray;
-import android.view.inputmethod.InputMethodSystemProperty;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -481,7 +480,7 @@
 
     @Override
     public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
-            boolean showImeSwitcher) {
+            boolean showImeSwitcher, boolean isMultiClientImeEnabled) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
             SomeArgs args = SomeArgs.obtain();
@@ -489,6 +488,7 @@
             args.argi2 = vis;
             args.argi3 = backDisposition;
             args.argi4 = showImeSwitcher ? 1 : 0;
+            args.argi5 = isMultiClientImeEnabled ? 1 : 0;
             args.arg1 = token;
             Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, args);
             m.sendToTarget();
@@ -801,11 +801,10 @@
     }
 
     private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition,
-            boolean showImeSwitcher) {
+            boolean showImeSwitcher, boolean isMultiClientImeEnabled) {
         if (displayId == INVALID_DISPLAY) return;
 
-        if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED
-                && mLastUpdatedImeDisplayId != displayId
+        if (!isMultiClientImeEnabled && mLastUpdatedImeDisplayId != displayId
                 && mLastUpdatedImeDisplayId != INVALID_DISPLAY) {
             // Set previous NavBar's IME window status as invisible when IME
             // window switched to another display for single-session IME case.
@@ -891,7 +890,8 @@
                     args = (SomeArgs) msg.obj;
                     handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */,
                             args.argi2 /* vis */, args.argi3 /* backDisposition */,
-                            args.argi4 != 0 /* showImeSwitcher */);
+                            args.argi4 != 0 /* showImeSwitcher */,
+                            args.argi5 != 0 /* isMultiClientImeEnabled */);
                     break;
                 case MSG_SHOW_RECENT_APPS:
                     for (int i = 0; i < mCallbacks.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index d939828..5adee40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -92,7 +92,7 @@
                     mInitialTouchY = y;
                     mInitialTouchX = x;
                     mDragDownCallback.onTouchSlopExceeded();
-                    return true;
+                    return mStartingChild != null || mDragDownCallback.isDragDownAnywhereEnabled();
                 }
                 break;
         }
@@ -162,7 +162,11 @@
         if (mStartingChild == null) {
             mStartingChild = findView(x, y);
             if (mStartingChild != null) {
-                mCallback.setUserLockedChild(mStartingChild, true);
+                if (mDragDownCallback.isDragDownEnabledForView(mStartingChild)) {
+                    mCallback.setUserLockedChild(mStartingChild, true);
+                } else {
+                    mStartingChild = null;
+                }
             }
         }
     }
@@ -237,6 +241,10 @@
         return mDraggingDown;
     }
 
+    public boolean isDragDownEnabled() {
+        return mDragDownCallback.isDragDownEnabledForView(null);
+    }
+
     public interface DragDownCallback {
 
         /**
@@ -253,5 +261,16 @@
         void onTouchSlopExceeded();
         void setEmptyDragAmount(float amount);
         boolean isFalsingCheckNeeded();
+
+        /**
+         * Is dragging down enabled on a given view
+         * @param view The view to check or {@code null} to check if it's enabled at all
+         */
+        boolean isDragDownEnabledForView(ExpandableView view);
+
+        /**
+         * @return if drag down is enabled anywhere, not just on selected views.
+         */
+        boolean isDragDownAnywhereEnabled();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index f34b912..3cb2a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -63,11 +63,6 @@
     int getMaxNotificationsWhileLocked(boolean recompute);
 
     /**
-     * True if the presenter is currently locked.
-     */
-    boolean isPresenterLocked();
-
-    /**
      * Called when the row states are updated by {@link NotificationViewHierarchyManager}.
      */
     void onUpdateRowStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 4ccd0cd..99682fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -374,6 +374,10 @@
         clipTransientViews();
 
         setClipTopAmount(clipTopAmount);
+        boolean isHidden = getViewState().hidden || clipTopAmount >= getIntrinsicHeight();
+        if (mShowNotificationShelf) {
+            setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE);
+        }
         setBackgroundTop(backgroundTop);
         setFirstElementRoundness(firstElementRoundness);
         mShelfIcons.setSpeedBumpIndex(mAmbientState.getSpeedBumpIndex());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 0d9f4e7..91d4707 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -153,6 +153,7 @@
                 if (primary == null) {
                     setAnimationPending(false);
                     invokeCallback(iRemoteAnimationFinishedCallback);
+                    mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
                     return;
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
index 16bd884..d9328fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
@@ -20,8 +20,12 @@
 import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -34,22 +38,33 @@
 
     private final UnlockMethodCache mUnlockMethodCache;
     private final NotificationLockscreenUserManager mLockscreenUserManager;
+    private final StatusBarStateController mStateController;
+    private final KeyguardMonitor mKeyguardMonitor;
     private ArraySet<Listener> mListeners = new ArraySet<>();
 
     private boolean mLastDynamicUnlocked;
     private boolean mCacheInvalid;
+    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     @Inject
     DynamicPrivacyController(Context context,
-            NotificationLockscreenUserManager notificationLockscreenUserManager) {
-        this(notificationLockscreenUserManager, UnlockMethodCache.getInstance(context));
+            KeyguardMonitor keyguardMonitor,
+            NotificationLockscreenUserManager notificationLockscreenUserManager,
+            StatusBarStateController stateController) {
+        this(notificationLockscreenUserManager, keyguardMonitor,
+                UnlockMethodCache.getInstance(context),
+                stateController);
     }
 
     @VisibleForTesting
     DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager,
-            UnlockMethodCache unlockMethodCache) {
+            KeyguardMonitor keyguardMonitor,
+            UnlockMethodCache unlockMethodCache,
+            StatusBarStateController stateController) {
         mLockscreenUserManager = notificationLockscreenUserManager;
+        mStateController = stateController;
         mUnlockMethodCache = unlockMethodCache;
+        mKeyguardMonitor = keyguardMonitor;
         mUnlockMethodCache.addListener(this);
         mLastDynamicUnlocked = isDynamicallyUnlocked();
     }
@@ -77,13 +92,39 @@
     }
 
     public boolean isDynamicallyUnlocked() {
-        return mUnlockMethodCache.canSkipBouncer() && isDynamicPrivacyEnabled();
+        return (mUnlockMethodCache.canSkipBouncer() || mKeyguardMonitor.isKeyguardGoingAway()
+                || mKeyguardMonitor.isKeyguardFadingAway())
+                && isDynamicPrivacyEnabled();
     }
 
     public void addListener(Listener listener) {
         mListeners.add(listener);
     }
 
+    /**
+     * Is the notification shade currently in a locked down mode where it's fully showing but the
+     * contents aren't revealed yet?
+     */
+    public boolean isInLockedDownShade() {
+        if (!mStatusBarKeyguardViewManager.isShowing()
+                || !mStatusBarKeyguardViewManager.isSecure()) {
+            return false;
+        }
+        int state = mStateController.getState();
+        if (state != StatusBarState.SHADE && state != StatusBarState.SHADE_LOCKED) {
+            return false;
+        }
+        if (!isDynamicPrivacyEnabled() || isDynamicallyUnlocked()) {
+            return false;
+        }
+        return true;
+    }
+
+    public void setStatusBarKeyguardViewManager(
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+    }
+
     public interface Listener {
         void onDynamicPrivacyChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 5bab0ef3..4fc6461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -32,7 +31,6 @@
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -51,6 +49,7 @@
 
     private static final String TAG = "InterruptionStateProvider";
     private static final boolean DEBUG = false;
+    private static final boolean DEBUG_HEADS_UP = true;
     private static final boolean ENABLE_HEADS_UP = true;
     private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
@@ -199,7 +198,7 @@
 
         boolean inShade = mStatusBarStateController.getState() == SHADE;
         if (entry.isBubble() && inShade) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: in unlocked shade where notification is shown as a "
                         + "bubble: " + sbn.getKey());
             }
@@ -207,7 +206,7 @@
         }
 
         if (!canAlertCommon(entry)) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: notification shouldn't alert: " + sbn.getKey());
             }
             return false;
@@ -218,7 +217,7 @@
         }
 
         if (entry.importance < NotificationManager.IMPORTANCE_HIGH) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey());
             }
             return false;
@@ -233,13 +232,16 @@
         boolean inUse = mPowerManager.isScreenOn() && !isDreaming;
 
         if (!inUse) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: not in use: " + sbn.getKey());
             }
             return false;
         }
 
         if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) {
+            if (DEBUG_HEADS_UP) {
+                Log.d(TAG, "No heads up: aborted by suppressor: " + sbn.getKey());
+            }
             return false;
         }
 
@@ -257,28 +259,28 @@
         StatusBarNotification sbn = entry.notification;
 
         if (!mAmbientDisplayConfiguration.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: disabled by setting: " + sbn.getKey());
             }
             return false;
         }
 
         if (!canAlertCommon(entry)) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: notification shouldn't alert: " + sbn.getKey());
             }
             return false;
         }
 
         if (entry.shouldSuppressAmbient()) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: ambient effect suppressed: " + sbn.getKey());
             }
             return false;
         }
 
         if (entry.importance < NotificationManager.IMPORTANCE_DEFAULT) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: not important enough: " + sbn.getKey());
             }
             return false;
@@ -300,7 +302,7 @@
         StatusBarNotification sbn = entry.notification;
 
         if (mNotificationFilter.shouldFilterOut(entry)) {
-            if (DEBUG) {
+            if (DEBUG || DEBUG_HEADS_UP) {
                 Log.d(TAG, "No alerting: filtered notification: " + sbn.getKey());
             }
             return false;
@@ -308,7 +310,7 @@
 
         // Don't alert notifications that are suppressed due to group alert behavior
         if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
-            if (DEBUG) {
+            if (DEBUG || DEBUG_HEADS_UP) {
                 Log.d(TAG, "No alerting: suppressed due to group alert behavior");
             }
             return false;
@@ -330,28 +332,28 @@
         StatusBarNotification sbn = entry.notification;
 
         if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: no huns or vr mode");
             }
             return false;
         }
 
         if (entry.shouldSuppressPeek()) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey());
             }
             return false;
         }
 
         if (isSnoozedPackage(sbn)) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: snoozed package: " + sbn.getKey());
             }
             return false;
         }
 
         if (entry.hasJustLaunchedFullScreenIntent()) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: recent fullscreen: " + sbn.getKey());
             }
             return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 6af1f5b..2f67f90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -147,6 +147,17 @@
         mHeadsUpManagerPhone.addListener(this)
         statusBarStateController.addCallback(this)
         mDozeParameters = DozeParameters.getInstance(mContext)
+        addListener(object : WakeUpListener {
+            override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
+                if (isFullyHidden && mNotificationsVisibleForExpansion) {
+                    // When the notification becomes fully invisible, let's make sure our expansion
+                    // flag also changes. This can happen if the bouncer shows when dragging down
+                    // and then the screen turning off, where we don't reset this state.
+                    setNotificationsVisibleForExpansion(visible = false, animate = false,
+                            increaseSpeed = false)
+                }
+            }
+        });
     }
 
     fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 8e68227..782aad1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -23,6 +23,7 @@
 import android.app.NotificationChannelGroup
 import android.app.NotificationManager.IMPORTANCE_NONE
 import android.content.Context
+import android.content.DialogInterface
 import android.graphics.Color
 import android.graphics.PixelFormat
 import android.graphics.drawable.Drawable
@@ -171,7 +172,6 @@
     private fun done() {
         resetState()
         dialog.dismiss()
-        onFinishListener?.onChannelEditorDialogFinished()
     }
 
     private fun resetState() {
@@ -261,6 +261,11 @@
         dialog.apply {
             setContentView(R.layout.notif_half_shelf)
             setCanceledOnTouchOutside(true)
+            setOnDismissListener(object : DialogInterface.OnDismissListener {
+                override fun onDismiss(dialog: DialogInterface?) {
+                    onFinishListener?.onChannelEditorDialogFinished()
+                }
+            })
             findViewById<ChannelEditorListView>(R.id.half_shelf_container).apply {
                 controller = this@ChannelEditorDialogController
                 appIcon = this@ChannelEditorDialogController.appIcon
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 18a51b9..6a611a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -179,6 +179,8 @@
      */
     private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
     private final KeyguardBypassController mKeyguardBypassController;
+    private final DynamicPrivacyController mDynamicPrivacyController;
+    private final SysuiStatusBarStateController mStatusbarStateController;
 
     private ExpandHelper mExpandHelper;
     private final NotificationSwipeHelper mSwipeHelper;
@@ -411,6 +413,7 @@
                 outline.setRoundRect(mBackgroundAnimationRect,
                         MathUtils.lerp(mCornerRadius / 2.0f, mCornerRadius,
                                 xProgress));
+                outline.setAlpha(1.0f - mAmbientState.getHideAmount());
             } else {
                 ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
             }
@@ -604,6 +607,8 @@
             }
         });
         dynamicPrivacyController.addListener(this);
+        mDynamicPrivacyController = dynamicPrivacyController;
+        mStatusbarStateController = (SysuiStatusBarStateController) statusBarStateController;
     }
 
     private void updateDismissRtlSetting(boolean dismissRtl) {
@@ -694,6 +699,9 @@
      */
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public boolean hasActiveClearableNotifications(@SelectedRows int selection) {
+        if (mDynamicPrivacyController.isInLockedDownShade()) {
+            return false;
+        }
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -1044,6 +1052,7 @@
         requestChildrenUpdate();
         updateFirstAndLastBackgroundViews();
         updateAlgorithmLayoutMinHeight();
+        updateOwnTranslationZ();
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4776,6 +4785,20 @@
         updateAlgorithmHeightAndPadding();
         updateBackgroundDimming();
         requestChildrenUpdate();
+        updateOwnTranslationZ();
+    }
+
+    private void updateOwnTranslationZ() {
+        // Since we are clipping to the outline we need to make sure that the shadows aren't
+        // clipped when pulsing
+        float ownTranslationZ = 0;
+        if (mKeyguardBypassController.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
+            ExpandableView firstChildNotGone = getFirstChildNotGone();
+            if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) {
+                ownTranslationZ = firstChildNotGone.getTranslationZ();
+            }
+        }
+        setTranslationZ(ownTranslationZ);
     }
 
     private void updateVisibility() {
@@ -5683,7 +5706,10 @@
             mAnimateBottomOnLayout = true;
         }
         // Let's update the footer once the notifications have been updated (in the next frame)
-        post(this::updateFooter);
+        post(() -> {
+            updateFooter();
+            updateSectionBoundaries();
+        });
     }
 
     public void setOnPulseHeightChangedListener(Runnable listener) {
@@ -6339,6 +6365,11 @@
                 }
 
                 return true;
+            } else if (mDynamicPrivacyController.isInLockedDownShade()) {
+                mStatusbarStateController.setLeaveOpenOnKeyguardHide(true);
+                mStatusBar.dismissKeyguardThenExecute(() -> false /* dismissAction */,
+                        null /* cancelRunnable */, false /* afterKeyguardGone */);
+                return true;
             } else {
                 // abort gesture.
                 return false;
@@ -6372,6 +6403,30 @@
         public boolean isFalsingCheckNeeded() {
             return mStatusBarState == StatusBarState.KEYGUARD;
         }
+
+        @Override
+        public boolean isDragDownEnabledForView(ExpandableView view) {
+            if (isDragDownAnywhereEnabled()) {
+                return true;
+            }
+            if (mDynamicPrivacyController.isInLockedDownShade()) {
+                if (view == null) {
+                    // Dragging down is allowed in general
+                    return true;
+                }
+                if (view instanceof ExpandableNotificationRow) {
+                    // Only drag down on sensitive views, otherwise the ExpandHelper will take this
+                    return ((ExpandableNotificationRow) view).getEntry().isSensitive();
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean isDragDownAnywhereEnabled() {
+            return mStatusbarStateController.getState() == StatusBarState.KEYGUARD
+                    && !mKeyguardBypassController.getBypassEnabled();
+        }
     };
 
     public DragDownCallback getDragDownCallback() { return mDragDownCallback; }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 7655056..ef80484 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -161,6 +161,7 @@
                 : 0;
         float clipStart = 0;
         int childCount = algorithmState.visibleChildren.size();
+        boolean firstHeadsUp = true;
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             ExpandableViewState state = child.getViewState();
@@ -173,7 +174,7 @@
             boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
                     && ((ExpandableNotificationRow) child).isPinned();
             if (mClipNotificationScrollToTop
-                    && (!state.inShelf || isHeadsUp)
+                    && (!state.inShelf || (isHeadsUp && !firstHeadsUp))
                     && newYTranslation < clipStart) {
                 // The previous view is overlapping on top, clip!
                 float overlapAmount = clipStart - newYTranslation;
@@ -181,7 +182,9 @@
             } else {
                 state.clipTopAmount = 0;
             }
-
+            if (isHeadsUp) {
+                firstHeadsUp = false;
+            }
             if (!child.isTransparent()) {
                 // Only update the previous values if we are not transparent,
                 // otherwise we would clip to a transparent view.
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 539bc7b..fce1dcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -14,8 +14,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.Interpolators.ALPHA_IN;
-import static com.android.systemui.Interpolators.ALPHA_OUT;
+import static com.android.systemui.Interpolators.LINEAR;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -23,6 +22,8 @@
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 
+import com.android.systemui.Dependency;
+import com.android.systemui.assist.AssistManager;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 
 import java.util.ArrayList;
@@ -32,12 +33,13 @@
  * multiples of the same nav bar icon appearing.
  */
 public class ButtonDispatcher {
-    private final static int FADE_DURATION_IN = 150;
-    private final static int FADE_DURATION_OUT = 100;
+    private static final int FADE_DURATION_IN = 150;
+    private static final int FADE_DURATION_OUT = 250;
 
     private final ArrayList<View> mViews = new ArrayList<>();
 
     private final int mId;
+    private final AssistManager mAssistManager;
 
     private View.OnClickListener mClickListener;
     private View.OnTouchListener mTouchListener;
@@ -55,7 +57,10 @@
     private AccessibilityDelegate mAccessibilityDelegate;
 
     private final ValueAnimator.AnimatorUpdateListener mAlphaListener = animation ->
-            setAlpha((float) animation.getAnimatedValue());
+            setAlpha(
+                    (float) animation.getAnimatedValue(),
+                    false /* animate */,
+                    false /* cancelAnimator */);
 
     private final AnimatorListenerAdapter mFadeListener = new AnimatorListenerAdapter() {
         @Override
@@ -67,6 +72,7 @@
 
     public ButtonDispatcher(int id) {
         mId = id;
+        mAssistManager = Dependency.get(AssistManager.class);
     }
 
     void clear() {
@@ -167,18 +173,32 @@
     }
 
     public void setAlpha(float alpha, boolean animate) {
-        setAlpha(alpha, animate, (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT);
+        setAlpha(alpha, animate, true /* cancelAnimator */);
     }
 
     public void setAlpha(float alpha, boolean animate, long duration) {
+        setAlpha(alpha, animate, duration, true /* cancelAnimator */);
+    }
+
+    public void setAlpha(float alpha, boolean animate, boolean cancelAnimator) {
+        setAlpha(
+                alpha,
+                animate,
+                (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT,
+                cancelAnimator);
+    }
+
+    public void setAlpha(float alpha, boolean animate, long duration, boolean cancelAnimator) {
+        if (mFadeAnimator != null && (cancelAnimator || animate)) {
+            mFadeAnimator.cancel();
+        }
         if (animate) {
-            if (mFadeAnimator != null) {
-                mFadeAnimator.cancel();
-            }
             setVisibility(View.VISIBLE);
             mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha);
+            mFadeAnimator.setStartDelay(
+                    mAssistManager.getAssistHandleShowAndGoRemainingDurationMs());
             mFadeAnimator.setDuration(duration);
-            mFadeAnimator.setInterpolator(getAlpha() < alpha ? ALPHA_IN : ALPHA_OUT);
+            mFadeAnimator.setInterpolator(LINEAR);
             mFadeAnimator.addListener(mFadeListener);
             mFadeAnimator.addUpdateListener(mAlphaListener);
             mFadeAnimator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 70d3bff..832ea9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -19,7 +19,6 @@
 import android.content.Context
 import android.content.pm.PackageManager
 import android.hardware.biometrics.BiometricSourceType
-import android.hardware.face.FaceManager
 import android.provider.Settings
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -34,6 +33,7 @@
 
     private val unlockMethodCache: UnlockMethodCache
     private val statusBarStateController: StatusBarStateController
+    private var hasFaceFeature: Boolean
 
     /**
      * The pending unlock type which is set if the bypass was blocked when it happened.
@@ -71,11 +71,8 @@
         unlockMethodCache = UnlockMethodCache.getInstance(context)
         this.statusBarStateController = statusBarStateController
 
-        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
-            return
-        }
-        val faceManager = context.getSystemService(FaceManager::class.java)
-        if (faceManager?.isHardwareDetected != true) {
+        hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)
+        if (!hasFaceFeature) {
             return
         }
 
@@ -165,7 +162,7 @@
         pw.print("  isPulseExpanding: "); pw.println(isPulseExpanding)
         pw.print("  launchingAffordance: "); pw.println(launchingAffordance)
         pw.print("  qSExpanded: "); pw.println(qSExpanded)
-        pw.print("  bouncerShowing: "); pw.println(bouncerShowing)
+        pw.print("  hasFaceFeature: "); pw.println(hasFaceFeature)
     }
 
     companion object {
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 c9c80d4..06a2225 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -338,8 +338,8 @@
         boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
                 || mShowingLaunchAffordance;
         if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
-            if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp())
-                    && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+            if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp()
+                    || mStatusBarStateController.getState() == StatusBarState.KEYGUARD)
                     && !mWakeUpCoordinator.getNotificationsFullyHidden()) {
                 invisible = true;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index c0a1b12..1d4d0bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -103,10 +103,11 @@
         final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.USER_SWITCHER_ENABLED, 0) != 0;
 
-        if (!UserManager.supportsMultipleUsers()
-                || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)
+        // TODO(b/138661450) Move IPC calls to background
+        if (!userSwitcherEnabled
+                || !UserManager.supportsMultipleUsers()
                 || UserManager.isDeviceInDemoMode(mContext)
-                || !userSwitcherEnabled) {
+                || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) {
             return false;
         }
 
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 081e293..6bfa048 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -323,7 +323,7 @@
 
     public void setComponents(NotificationPanelView panel, AssistManager assistManager) {
         mPanelView = panel;
-        updateSystemUiStateFlags();
+        updatePanelSystemUiStateFlags();
     }
 
     @Override
@@ -587,7 +587,7 @@
         updateNavButtonIcons();
         updateSlippery();
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
-        updateSystemUiStateFlags();
+        updateDisabledSystemUiStateFlags();
     }
 
     public void updateNavButtonIcons() {
@@ -710,10 +710,10 @@
 
     public void onStatusBarPanelStateChanged() {
         updateSlippery();
-        updateSystemUiStateFlags();
+        updatePanelSystemUiStateFlags();
     }
 
-    public void updateSystemUiStateFlags() {
+    public void updateDisabledSystemUiStateFlags() {
         int displayId = mContext.getDisplayId();
         mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING,
                 ActivityManagerWrapper.getInstance().isScreenPinningActive(), displayId);
@@ -723,6 +723,10 @@
                 (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0, displayId);
         mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SEARCH_DISABLED,
                 (mDisabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0, displayId);
+    }
+
+    public void updatePanelSystemUiStateFlags() {
+        int displayId = mContext.getDisplayId();
         if (mPanelView != null) {
             mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
                     mPanelView.isFullyExpanded() && !mPanelView.isInSettings(), displayId);
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 792b83a..c171730 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -40,6 +40,8 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.MathUtils;
@@ -53,6 +55,7 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardClockSwitch;
@@ -134,11 +137,19 @@
      */
     public static final int FLING_HIDE = 2;
 
+    private double mQqsSplitFraction;
+
     // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
     // changed.
     private static final int CAP_HEIGHT = 1456;
     private static final int FONT_HEIGHT = 2163;
 
+    /**
+     * Maximum time before which we will expand the panel even for slow motions when getting a
+     * touch passed over from launcher.
+     */
+    private static final int MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER = 300;
+
     static final String COUNTER_PANEL_OPEN = "panel_open";
     static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
     private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
@@ -374,6 +385,8 @@
     private boolean mHeadsUpPinnedMode;
     private float mKeyguardHeadsUpShowingAmount = 0.0f;
     private boolean mShowingKeyguardHeadsUp;
+    private boolean mAllowExpandForSmallExpansion;
+    private Runnable mExpandAfterLayoutRunnable;
 
     @Inject
     public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -518,6 +531,9 @@
                 com.android.internal.R.dimen.status_bar_height);
         mHeadsUpInset = statusbarHeight + getResources().getDimensionPixelSize(
                 R.dimen.heads_up_status_bar_padding);
+        mQqsSplitFraction = ((float) getResources().getInteger(R.integer.qqs_split_fraction)) / (
+                getResources().getInteger(R.integer.qqs_split_fraction)
+                        + getResources().getInteger(R.integer.qs_split_fraction));
     }
 
     /**
@@ -671,6 +687,10 @@
         }
         updateMaxHeadsUpTranslation();
         updateGestureExclusionRect();
+        if (mExpandAfterLayoutRunnable != null) {
+            mExpandAfterLayoutRunnable.run();
+            mExpandAfterLayoutRunnable = null;
+        }
     }
 
     private void updateGestureExclusionRect() {
@@ -1069,6 +1089,8 @@
             mDownY = event.getY();
             mCollapsedOnDown = isFullyCollapsed();
             mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
+            mAllowExpandForSmallExpansion = mExpectingSynthesizedDown;
+            mTouchSlopExceededBeforeDown = mExpectingSynthesizedDown;
             if (mExpectingSynthesizedDown) {
                 mLastEventSynthesizedDown = true;
             } else {
@@ -1127,6 +1149,20 @@
     }
 
     @Override
+    protected boolean shouldExpandWhenNotFlinging() {
+        if (super.shouldExpandWhenNotFlinging()) {
+            return true;
+        }
+        if (mAllowExpandForSmallExpansion) {
+            // When we get a touch that came over from launcher, the velocity isn't always correct
+            // Let's err on expanding if the gesture has been reasonably slow
+            long timeSinceDown = SystemClock.uptimeMillis() - mDownTime;
+            return timeSinceDown <= MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER;
+        }
+        return false;
+    }
+
+    @Override
     protected float getOpeningHeight() {
         return mNotificationStackScroller.getOpeningHeight();
     }
@@ -1230,6 +1266,15 @@
             // earlier so the state is already up to date when dragging down.
             setListening(true);
         }
+        if (isQsSplitEnabled() && !mKeyguardShowing) {
+            if (mQsExpandImmediate) {
+                mNotificationStackScroller.setVisibility(View.GONE);
+                mQsFrame.setVisibility(View.VISIBLE);
+            } else {
+                mNotificationStackScroller.setVisibility(View.VISIBLE);
+                mQsFrame.setVisibility(View.GONE);
+            }
+        }
         return false;
     }
 
@@ -1240,6 +1285,17 @@
                 || y <= mQs.getView().getY() + mQs.getView().getHeight());
     }
 
+    private boolean isOnQsEndArea(float x) {
+        if (!isQsSplitEnabled()) return false;
+        if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
+            return x >= mQsFrame.getX() + mQqsSplitFraction * mQsFrame.getWidth()
+                    && x <= mQsFrame.getX() + mQsFrame.getWidth();
+        } else {
+            return x >= mQsFrame.getX()
+                    && x <= mQsFrame.getX() + (1 - mQqsSplitFraction) * mQsFrame.getWidth();
+        }
+    }
+
     private boolean isOpenQsEvent(MotionEvent event) {
         final int pointerCount = event.getPointerCount();
         final int action = event.getActionMasked();
@@ -1255,7 +1311,9 @@
                 && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
                 || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
 
-        return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag;
+        final boolean onHeaderRight = isOnQsEndArea(event.getX());
+
+        return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag || onHeaderRight;
     }
 
     private void handleQsDown(MotionEvent event) {
@@ -1299,10 +1357,19 @@
      *
      * @param velocity unit is in px / millis
      */
-    public void stopWaitingForOpenPanelGesture(float velocity) {
+    public void stopWaitingForOpenPanelGesture(final float velocity) {
         if (mExpectingSynthesizedDown) {
             mExpectingSynthesizedDown = false;
-            fling(velocity > 1f ? 1000f * velocity : 0, true /* animate */);
+            maybeVibrateOnOpening();
+            Runnable runnable = () -> fling(velocity > 1f ? 1000f * velocity : 0,
+                    true /* expand */);
+            if (mStatusBar.getStatusBarWindow().getHeight()
+                    != mStatusBar.getStatusBarHeight()) {
+                // The panel is already expanded to its full size, let's expand directly
+                runnable.run();
+            } else {
+                mExpandAfterLayoutRunnable = runnable;
+            }
             onTrackingStopped(false);
         }
     }
@@ -1481,6 +1548,10 @@
 
         mBarState = statusBarState;
         mKeyguardShowing = keyguardShowing;
+        if (mKeyguardShowing && isQsSplitEnabled()) {
+            mNotificationStackScroller.setVisibility(View.VISIBLE);
+            mQsFrame.setVisibility(View.VISIBLE);
+        }
 
         if (oldState == StatusBarState.KEYGUARD
                 && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
@@ -1500,6 +1571,7 @@
         } else {
             mKeyguardStatusBar.setAlpha(1f);
             mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
+            ((PhoneStatusBarView) mBar).maybeShowDivider(keyguardShowing);
             if (keyguardShowing && oldState != mBarState) {
                 if (mQs != null) {
                     mQs.hideImmediately();
@@ -1929,7 +2001,8 @@
      * @return Whether we should intercept a gesture to open Quick Settings.
      */
     private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
-        if (!mQsExpansionEnabled || mCollapsedOnDown) {
+        if (!mQsExpansionEnabled || mCollapsedOnDown
+                || (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled())) {
             return false;
         }
         View header = mKeyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader();
@@ -3059,10 +3132,8 @@
 
     /**
      * Whether the camera application can be launched for the camera launch gesture.
-     *
-     * @param keyguardIsShowing whether keyguard is being shown
      */
-    public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
+    public boolean canCameraGestureBeLaunched() {
         if (!mStatusBar.isCameraAllowedByAdmin()) {
             return false;
         }
@@ -3071,7 +3142,7 @@
         String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
                 ? null : resolveInfo.activityInfo.packageName;
         return packageToLaunch != null &&
-                (keyguardIsShowing || !isForegroundApp(packageToLaunch))
+                (mBarState != StatusBarState.SHADE || !isForegroundApp(packageToLaunch))
                 && !mAffordanceHelper.isSwipingInProgress();
     }
 
@@ -3385,4 +3456,8 @@
         mOnReinflationListener = onReinflationListener;
     }
 
+    public static boolean isQsSplitEnabled() {
+        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+                SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED, false);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 727f72b..31600e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -61,7 +61,8 @@
     private static final int INITIAL_OPENING_PEEK_DURATION = 200;
     private static final int PEEK_ANIMATION_DURATION = 360;
     private static final int NO_FIXED_DURATION = -1;
-    private long mDownTime;
+    protected long mDownTime;
+    protected boolean mTouchSlopExceededBeforeDown;
     private float mMinExpandHeight;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mPanelUpdateWhenAnimatorEnds;
@@ -322,7 +323,7 @@
                 if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)
                         || mPeekAnimator != null) {
                     mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
-                            || mPeekAnimator != null;
+                            || mPeekAnimator != null || mTouchSlopExceededBeforeDown;
                     cancelHeightAnimator();
                     cancelPeek();
                     onTrackingStarted();
@@ -408,9 +409,7 @@
         runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
                 false /* collapseWhenFinished */);
         notifyBarPanelExpansionChanged();
-        if (mVibrateOnOpening) {
-            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
-        }
+        maybeVibrateOnOpening();
 
         //TODO: keyguard opens QS a different way; log that too?
 
@@ -425,6 +424,12 @@
                 rot);
     }
 
+    protected void maybeVibrateOnOpening() {
+        if (mVibrateOnOpening) {
+            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+        }
+    }
+
     protected abstract float getOpeningHeight();
 
     /**
@@ -576,7 +581,7 @@
                 mInitialTouchY = y;
                 mInitialTouchX = x;
                 mTouchStartedInEmptyArea = !isInContentBounds(x, y);
-                mTouchSlopExceeded = false;
+                mTouchSlopExceeded = mTouchSlopExceededBeforeDown;
                 mJustPeeked = false;
                 mMotionAborted = false;
                 mPanelClosedOnDown = isFullyCollapsed();
@@ -679,12 +684,16 @@
             return true;
         }
         if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
-            return getExpandedFraction() > 0.5f;
+            return shouldExpandWhenNotFlinging();
         } else {
             return vel > 0;
         }
     }
 
+    protected boolean shouldExpandWhenNotFlinging() {
+        return getExpandedFraction() > 0.5f;
+    }
+
     /**
      * @param x the final x-coordinate when the finger was lifted
      * @param y the final y-coordinate when the finger was lifted
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index a7d5aca..96b4b22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -32,7 +32,7 @@
     private final PhoneStatusBarView mView;
     private final float mIconAlphaWhenOpaque;
 
-    private View mLeftSide, mStatusIcons, mBattery, mClock;
+    private View mLeftSide, mStatusIcons, mBattery, mClock, mDivider;
     private Animator mCurrentAnimation;
 
     public PhoneStatusBarTransitions(PhoneStatusBarView view) {
@@ -46,6 +46,7 @@
         mLeftSide = mView.findViewById(R.id.status_bar_left_side);
         mStatusIcons = mView.findViewById(R.id.statusIcons);
         mBattery = mView.findViewById(R.id.battery);
+        mDivider = mView.findViewById(R.id.divider);
         applyModeBackground(-1, getMode(), false /*animate*/);
         applyMode(getMode(), false /*animate*/);
     }
@@ -88,6 +89,7 @@
             anims.playTogether(
                     animateTransitionTo(mLeftSide, newAlpha),
                     animateTransitionTo(mStatusIcons, newAlpha),
+                    animateTransitionTo(mDivider, newAlpha),
                     animateTransitionTo(mBattery, newAlphaBC)
                     );
             if (isLightsOut(mode)) {
@@ -98,6 +100,7 @@
         } else {
             mLeftSide.setAlpha(newAlpha);
             mStatusIcons.setAlpha(newAlpha);
+            mDivider.setAlpha(newAlpha);
             mBattery.setAlpha(newAlphaBC);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 8efd952..53e1467 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -26,6 +26,7 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.provider.DeviceConfig;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Pair;
@@ -40,6 +41,8 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.systemui.DarkReceiverImpl;
 import com.android.systemui.Dependency;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
@@ -78,6 +81,10 @@
     private View mCutoutSpace;
     @Nullable
     private DisplayCutout mDisplayCutout;
+
+    private DarkReceiverImpl mSplitDivider;
+    private View mDividerContainer;
+    private QsSplitPropertyListener mPropertyListener;
     /**
      * Draw this many pixels into the left/right side of the cutout to optimally use the space
      */
@@ -109,6 +116,10 @@
         mBattery = findViewById(R.id.battery);
         mCutoutSpace = findViewById(R.id.cutout_space_view);
         mCenterIconSpace = findViewById(R.id.centered_icon_area);
+        mSplitDivider = findViewById(R.id.divider);
+        mDividerContainer = findViewById(R.id.divider_container);
+        maybeShowDivider(true);
+        mPropertyListener = new QsSplitPropertyListener(mDividerContainer);
 
         updateResources();
     }
@@ -118,16 +129,26 @@
         super.onAttachedToWindow();
         // Always have Battery meters in the status bar observe the dark/light modes.
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
+        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mSplitDivider);
+        maybeShowDivider(true);
         if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) {
             updateLayoutForCutout();
         }
+        if (mPropertyListener != null) {
+            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+                    mContext.getMainExecutor(), mPropertyListener);
+        }
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery);
+        Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mSplitDivider);
         mDisplayCutout = null;
+        if (mPropertyListener != null) {
+            DeviceConfig.removeOnPropertiesChangedListener(mPropertyListener);
+        }
     }
 
     @Override
@@ -196,6 +217,7 @@
     public void onPanelPeeked() {
         super.onPanelPeeked();
         mBar.makeExpandedVisible(false);
+        maybeShowDivider(!mBar.mPanelExpanded);
     }
 
     @Override
@@ -204,6 +226,7 @@
         // Close the status bar in the next frame so we can show the end of the animation.
         post(mHideExpandedRunnable);
         mIsFullyOpenedPanel = false;
+        maybeShowDivider(!mBar.mPanelExpanded);
     }
 
     public void removePendingHideExpandedRunnables() {
@@ -217,6 +240,7 @@
             mPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
         mIsFullyOpenedPanel = true;
+        maybeShowDivider(!mBar.mPanelExpanded);
     }
 
     @Override
@@ -240,24 +264,28 @@
         mBar.onTrackingStarted();
         mScrimController.onTrackingStarted();
         removePendingHideExpandedRunnables();
+        maybeShowDivider(!mBar.mPanelExpanded);
     }
 
     @Override
     public void onClosingFinished() {
         super.onClosingFinished();
         mBar.onClosingFinished();
+        maybeShowDivider(!mBar.mPanelExpanded);
     }
 
     @Override
     public void onTrackingStopped(boolean expand) {
         super.onTrackingStopped(expand);
         mBar.onTrackingStopped(expand);
+        maybeShowDivider(!mBar.mPanelExpanded);
     }
 
     @Override
     public void onExpandingFinished() {
         super.onExpandingFinished();
         mScrimController.onExpandingFinished();
+        maybeShowDivider(!mBar.mPanelExpanded);
     }
 
     @Override
@@ -390,4 +418,30 @@
     protected boolean shouldPanelBeVisible() {
         return mHeadsUpVisible || super.shouldPanelBeVisible();
     }
+
+    void maybeShowDivider(boolean showDivider) {
+        int state =
+                showDivider && NotificationPanelView.isQsSplitEnabled() ? View.VISIBLE : View.GONE;
+        mDividerContainer.setVisibility(state);
+    }
+
+    private static class QsSplitPropertyListener implements
+            DeviceConfig.OnPropertiesChangedListener {
+        private final View mDivider;
+
+        QsSplitPropertyListener(View divider) {
+            mDivider = divider;
+        }
+
+        @Override
+        public void onPropertiesChanged(DeviceConfig.Properties properties) {
+            if (properties.getNamespace().equals(DeviceConfig.NAMESPACE_SYSTEMUI)
+                    && properties.getKeyset().contains(
+                    SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED)) {
+                boolean splitEnabled = properties.getBoolean(
+                        SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED, false);
+                mDivider.setVisibility(splitEnabled ? VISIBLE : GONE);
+            }
+        }
+    }
 }
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 f15b601..4f9df43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -193,6 +193,7 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationClicker;
@@ -375,6 +376,8 @@
     @Inject
     protected HeadsUpManagerPhone mHeadsUpManager;
     @Inject
+    DynamicPrivacyController mDynamicPrivacyController;
+    @Inject
     BypassHeadsUpNotifier mBypassHeadsUpNotifier;
     @Nullable
     @Inject
@@ -591,7 +594,7 @@
     private boolean mVibrateOnOpening;
     private VibratorHelper mVibratorHelper;
     private ActivityLaunchAnimator mActivityLaunchAnimator;
-    protected NotificationPresenter mPresenter;
+    protected StatusBarNotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
     private boolean mPulsing;
     protected BubbleController mBubbleController;
@@ -1066,7 +1069,7 @@
 
         mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
                 mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
-                mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager,
+                mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
                 mNotificationAlertingManager, rowBinder);
 
         mNotificationListController =
@@ -1243,6 +1246,7 @@
                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
+        mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
 
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
         mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
@@ -3785,10 +3789,8 @@
             mLaunchCameraOnFinishedGoingToSleep = true;
             return;
         }
-        if (!mNotificationPanel.canCameraGestureBeLaunched(
-                mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
-            if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " +
-                    mExpandedVisible);
+        if (!mNotificationPanel.canCameraGestureBeLaunched()) {
+            if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now");
             return;
         }
         if (!mDeviceInteractive) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index a87dca4..a870590 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -59,6 +59,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -117,9 +118,9 @@
     private final AccessibilityManager mAccessibilityManager;
     private final KeyguardManager mKeyguardManager;
     private final ActivityLaunchAnimator mActivityLaunchAnimator;
-    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final int mMaxAllowedKeyguardNotifications;
     private final IStatusBarService mBarService;
+    private final DynamicPrivacyController mDynamicPrivacyController;
     private boolean mReinflateNotificationsOnUserSwitched;
     private boolean mDispatchUiModeChangeOnUserSwitched;
     private final UnlockMethodCache mUnlockMethodCache;
@@ -136,16 +137,16 @@
             DozeScrimController dozeScrimController,
             ScrimController scrimController,
             ActivityLaunchAnimator activityLaunchAnimator,
-            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            DynamicPrivacyController dynamicPrivacyController,
             NotificationAlertingManager notificationAlertingManager,
             NotificationRowBinderImpl notificationRowBinder) {
         mContext = context;
         mNotificationPanel = panel;
         mHeadsUpManager = headsUp;
+        mDynamicPrivacyController = dynamicPrivacyController;
         mCommandQueue = getComponent(context, CommandQueue.class);
         mAboveShelfObserver = new AboveShelfObserver(stackScroller);
         mActivityLaunchAnimator = activityLaunchAnimator;
-        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mAboveShelfObserver.setListener(statusBarWindow.findViewById(
                 R.id.notification_container_parent));
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -454,8 +455,15 @@
     @Override
     public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) {
         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
-        if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) {
-            mShadeController.goToLockedShade(clickedEntry.getRow());
+        if (nowExpanded) {
+            if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+                mShadeController.goToLockedShade(clickedEntry.getRow());
+            } else if (clickedEntry.isSensitive()
+                    && mDynamicPrivacyController.isInLockedDownShade()) {
+                mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+                mActivityStarter.dismissKeyguardThenExecute(() -> false /* dismissAction */
+                        , null /* cancelRunnable */, false /* afterKeyguardGone */);
+            }
         }
     }
 
@@ -464,12 +472,6 @@
         return mVrMode;
     }
 
-    @Override
-    public boolean isPresenterLocked() {
-        return mStatusBarKeyguardViewManager.isShowing()
-                && mStatusBarKeyguardViewManager.isSecure();
-    }
-
     private void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
         mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
         mActivityStarter.dismissKeyguardThenExecute(dismissAction, null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index d9a9f7c..0ef981b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -29,7 +29,9 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.util.Log;
+import android.view.Display;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -57,6 +59,7 @@
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Arrays;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -73,11 +76,13 @@
     private final WindowManager mWindowManager;
     private final IActivityManager mActivityManager;
     private final DozeParameters mDozeParameters;
-    private final WindowManager.LayoutParams mLpChanged;
+    private final LayoutParams mLpChanged;
     private final boolean mKeyguardScreenRotation;
     private final long mLockScreenDisplayTimeout;
+    private final Display.Mode mKeyguardDisplayMode;
+    private final KeyguardBypassController mKeyguardBypassController;
     private ViewGroup mStatusBarView;
-    private WindowManager.LayoutParams mLp;
+    private LayoutParams mLp;
     private boolean mHasTopUi;
     private boolean mHasTopUiChanged;
     private int mBarHeight;
@@ -91,27 +96,49 @@
     private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
 
     @Inject
-    public StatusBarWindowController(Context context) {
+    public StatusBarWindowController(Context context,
+            StatusBarStateController statusBarStateController,
+            ConfigurationController configurationController,
+            KeyguardBypassController keyguardBypassController) {
         this(context, context.getSystemService(WindowManager.class), ActivityManager.getService(),
-                DozeParameters.getInstance(context));
+                DozeParameters.getInstance(context), statusBarStateController,
+                configurationController, keyguardBypassController);
     }
 
     @VisibleForTesting
     public StatusBarWindowController(Context context, WindowManager windowManager,
-            IActivityManager activityManager, DozeParameters dozeParameters) {
+            IActivityManager activityManager, DozeParameters dozeParameters,
+            StatusBarStateController statusBarStateController,
+            ConfigurationController configurationController,
+            KeyguardBypassController keyguardBypassController) {
         mContext = context;
         mWindowManager = windowManager;
         mActivityManager = activityManager;
         mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
         mDozeParameters = dozeParameters;
         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
-        mLpChanged = new WindowManager.LayoutParams();
+        mLpChanged = new LayoutParams();
+        mKeyguardBypassController = keyguardBypassController;
         mLockScreenDisplayTimeout = context.getResources()
                 .getInteger(R.integer.config_lockScreenDisplayTimeout);
-        ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
+        ((SysuiStatusBarStateController) statusBarStateController)
                 .addCallback(mStateListener,
                         SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
-        Dependency.get(ConfigurationController.class).addCallback(this);
+        configurationController.addCallback(this);
+
+        Display.Mode[] supportedModes = context.getDisplay().getSupportedModes();
+        Display.Mode currentMode = context.getDisplay().getMode();
+        // Running on the highest frame rate available can be expensive.
+        // Let's specify a preferred refresh rate, and allow higher FPS only when we
+        // know that we're not falsing (because we unlocked.)
+        int keyguardRefreshRate = context.getResources()
+                .getInteger(R.integer.config_keyguardRefreshRate);
+        // Find supported display mode with the same resolution and requested refresh rate.
+        mKeyguardDisplayMode = Arrays.stream(supportedModes).filter(mode ->
+                (int) mode.getRefreshRate() == keyguardRefreshRate
+                        && mode.getPhysicalWidth() == currentMode.getPhysicalWidth()
+                        && mode.getPhysicalHeight() == currentMode.getPhysicalHeight())
+                .findFirst().orElse(null);
     }
 
     /**
@@ -144,19 +171,19 @@
         // Now that the status bar window encompasses the sliding panel and its
         // translucent backdrop, the entire thing is made TRANSLUCENT and is
         // hardware-accelerated.
-        mLp = new WindowManager.LayoutParams(
+        mLp = new LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 barHeight,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                LayoutParams.TYPE_STATUS_BAR,
+                LayoutParams.FLAG_NOT_FOCUSABLE
+                        | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+                        | LayoutParams.FLAG_SPLIT_TOUCH
+                        | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                        | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 PixelFormat.TRANSLUCENT);
         mLp.token = new Binder();
         mLp.gravity = Gravity.TOP;
-        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
         mLp.setTitle("StatusBar");
         mLp.packageName = mContext.getPackageName();
         mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -189,9 +216,9 @@
 
     private void applyKeyguardFlags(State state) {
         if (state.keyguardShowing) {
-            mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+            mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_KEYGUARD;
         } else {
-            mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+            mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_KEYGUARD;
         }
 
         final boolean scrimsOccludingWallpaper =
@@ -199,9 +226,9 @@
         final boolean keyguardOrAod = state.keyguardShowing
                 || (state.dozing && mDozeParameters.getAlwaysOn());
         if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) {
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+            mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER;
         } else {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+            mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
         }
 
         if (state.dozing) {
@@ -209,6 +236,18 @@
         } else {
             mLpChanged.privateFlags &= ~LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
         }
+
+        if (mKeyguardDisplayMode != null) {
+            boolean bypassOnKeyguard = mKeyguardBypassController.getBypassEnabled()
+                    && state.statusBarState == StatusBarState.KEYGUARD && !state.keyguardFadingAway
+                    && !state.keyguardGoingAway;
+            if (state.dozing || bypassOnKeyguard) {
+                mLpChanged.preferredDisplayModeId = mKeyguardDisplayMode.getModeId();
+            } else {
+                mLpChanged.preferredDisplayModeId = 0;
+            }
+            Trace.setCounter("display_mode_id", mLpChanged.preferredDisplayModeId);
+        }
     }
 
     private void adjustScreenOrientation(State state) {
@@ -228,17 +267,17 @@
         if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput)
                 || ENABLE_REMOTE_INPUT && state.remoteInputActive
                 || state.bubbleExpanded) {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLpChanged.flags |= LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else {
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            mLpChanged.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         }
 
-        mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        mLpChanged.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
     }
 
     private void applyForceShowNavigationFlag(State state) {
@@ -296,19 +335,19 @@
                 && state.statusBarState == StatusBarState.KEYGUARD
                 && !state.qsExpanded && !state.forceUserActivity) {
             mLpChanged.inputFeatures |=
-                    WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+                    LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
         } else {
             mLpChanged.inputFeatures &=
-                    ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+                    ~LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
         }
     }
 
     private void applyStatusBarColorSpaceAgnosticFlag(State state) {
         if (!isExpanded(state)) {
-            mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
+            mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
         } else {
             mLpChanged.privateFlags &=
-                    ~WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
+                    ~LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
         }
     }
 
@@ -357,16 +396,16 @@
             mLpChanged.privateFlags |= WindowManager
                     .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
         } else {
-            mLpChanged.privateFlags &= ~WindowManager
-                    .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+            mLpChanged.privateFlags
+                    &= ~LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
         }
     }
 
     private void applyModalFlag(State state) {
         if (state.headsUpShowing) {
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCH_MODAL;
         } else {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCH_MODAL;
         }
     }
 
@@ -374,12 +413,12 @@
         if (state.forceDozeBrightness) {
             mLpChanged.screenBrightness = mScreenBrightnessDoze;
         } else {
-            mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
+            mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
         }
     }
 
     private void applyHasTopUi(State state) {
-        mHasTopUiChanged = isExpanded(state);
+        mHasTopUiChanged = state.forceHasTopUi || isExpanded(state);
     }
 
     private void applyNotTouchable(State state) {
@@ -575,7 +614,8 @@
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("StatusBarWindowController state:");
+        pw.println("StatusBarWindowController:");
+        pw.println("  mKeyguardDisplayMode=" + mKeyguardDisplayMode);
         pw.println(mCurrentState);
     }
 
@@ -594,6 +634,23 @@
         setKeyguardDark(useDarkText);
     }
 
+    /**
+     * When keyguard will be dismissed but didn't start animation yet.
+     */
+    public void setKeyguardGoingAway(boolean goingAway) {
+        mCurrentState.keyguardGoingAway = goingAway;
+        apply(mCurrentState);
+    }
+
+    public boolean getForceHasTopUi() {
+        return mCurrentState.forceHasTopUi;
+    }
+
+    public void setForceHasTopUi(boolean forceHasTopUi) {
+        mCurrentState.forceHasTopUi = forceHasTopUi;
+        apply(mCurrentState);
+    }
+
     private static class State {
         boolean keyguardShowing;
         boolean keyguardOccluded;
@@ -603,6 +660,7 @@
         boolean statusBarFocusable;
         boolean bouncerShowing;
         boolean keyguardFadingAway;
+        boolean keyguardGoingAway;
         boolean qsExpanded;
         boolean headsUpShowing;
         boolean forceStatusBarVisible;
@@ -614,6 +672,7 @@
         boolean notTouchable;
         boolean bubblesShowing;
         boolean bubbleExpanded;
+        boolean forceHasTopUi;
 
         /**
          * The {@link StatusBar} state from the status bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 33b863f..6789930 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -66,6 +66,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
 import com.android.systemui.tuner.TunerService;
@@ -416,9 +417,8 @@
         }
         boolean intercept = false;
         if (mNotificationPanel.isFullyExpanded()
-                && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+                && mDragDownHelper.isDragDownEnabled()
                 && !mService.isBouncerShowing()
-                && (!mBypassController.getBypassEnabled() || mNotificationPanel.isQsExpanded())
                 && !mService.isDozing()) {
             intercept = mDragDownHelper.onInterceptTouchEvent(ev);
         }
@@ -441,9 +441,7 @@
         if (mService.isDozing()) {
             handled = !mService.isPulsing();
         }
-        if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled
-                && !mBypassController.getBypassEnabled())
-                || mDragDownHelper.isDraggingDown()) {
+        if ((mDragDownHelper.isDragDownEnabled() && !handled) || mDragDownHelper.isDraggingDown()) {
             // we still want to finish our drag down gesture when locking the screen
             handled = mDragDownHelper.onTouchEvent(ev);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 3f3e1e3..a6b5b38 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -43,6 +43,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
@@ -275,14 +276,14 @@
     }
 
     public boolean areCaptionsEnabled() {
-        int currentValue = Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.ODI_CAPTIONS_ENABLED, 0);
+        int currentValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_ENABLED, 0, UserHandle.USER_CURRENT);
         return currentValue == 1;
     }
 
     public void setCaptionsEnabled(boolean isEnabled) {
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0);
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0, UserHandle.USER_CURRENT);
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index db45ad78..0044ca7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -36,6 +36,7 @@
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
+import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -65,6 +66,8 @@
 public class CarrierTextControllerTest extends SysuiTestCase {
 
     private static final CharSequence SEPARATOR = " \u2014 ";
+    private static final CharSequence INVALID_CARD_TEXT = "Invalid card";
+    private static final CharSequence AIRPLANE_MODE_TEXT = "Airplane mode";
     private static final String TEST_CARRIER = "TEST_CARRIER";
     private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
     private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
@@ -106,6 +109,10 @@
         mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager);
         mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager);
         mContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.string.keyguard_sim_error_message_short, INVALID_CARD_TEXT);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.string.airplane_mode, AIRPLANE_MODE_TEXT);
         mDependency.injectMockDependency(WakefulnessLifecycle.class);
         mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
                 new Handler(mTestableLooper.getLooper()));
@@ -122,6 +129,53 @@
     }
 
     @Test
+    public void testAirplaneMode() {
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        mCarrierTextController.updateCarrierText();
+
+        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextController.CarrierTextCallbackInfo.class);
+
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText);
+    }
+
+    @Test
+    public void testCardIOError() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn(
+                IccCardConstants.State.CARD_IO_ERROR);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        mCarrierTextController.mCallback.onSimStateChanged(3, 1,
+                IccCardConstants.State.CARD_IO_ERROR);
+
+        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextController.CarrierTextCallbackInfo.class);
+
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertEquals("TEST_CARRIER" + SEPARATOR + INVALID_CARD_TEXT, captor.getValue().carrierText);
+        // There's only one subscription in the list
+        assertEquals(1, captor.getValue().listOfCarriers.length);
+        assertEquals(TEST_CARRIER, captor.getValue().listOfCarriers[0]);
+    }
+
+    @Test
     public void testWrongSlots() {
         reset(mCarrierTextCallback);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt
index cca35ca..d921d58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt
@@ -18,7 +18,6 @@
 
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
-import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -37,6 +36,7 @@
     private lateinit var controller: DumpController
     @Mock private lateinit var callback1: Dumpable
     @Mock private lateinit var callback2: Dumpable
+    @Mock private lateinit var callback3: Dumpable
     @Mock private lateinit var fd: FileDescriptor
     @Mock private lateinit var pw: PrintWriter
     private val args = emptyArray<String>()
@@ -46,26 +46,19 @@
         MockitoAnnotations.initMocks(this)
 
         controller = DumpController()
-//        Debug.waitForDebugger()
     }
 
-    @Test
+    @Test(expected = IllegalArgumentException::class)
     fun testListenerOnlyAddedOnce() {
-        controller.apply {
-            addListener(callback1)
-            addListener(callback1)
-        }
-        assertEquals(1, controller.numListeners)
-
-        controller.dump(fd, pw, args)
-        verify(callback1 /* only once */).dump(fd, pw, args)
+        controller.registerDumpable("cb1", callback1)
+        controller.registerDumpable("cb1", callback2)
     }
 
     @Test
     fun testListenersCalledOnDump() {
         controller.apply {
-            addListener(callback1)
-            addListener(callback2)
+            registerDumpable("cb1", callback1)
+            registerDumpable("cb2", callback2)
         }
 
         controller.dump(fd, pw, args)
@@ -75,11 +68,59 @@
     }
 
     @Test
+    fun testListenersAreFiltered() {
+        controller.apply {
+            registerDumpable("cb1", callback1)
+            registerDumpable("cb2", callback2)
+            registerDumpable("cb3", callback3)
+        }
+
+        val args = arrayOf("dependency", "DumpController", "cb3,cb1")
+        controller.dump(fd, pw, args)
+
+        verify(callback1 /* only once */).dump(fd, pw, args)
+        verify(callback2, never()).dump(fd, pw, args)
+        verify(callback3 /* only once */).dump(fd, pw, args)
+    }
+
+    @Test
+    fun testFiltersAreNotCaseSensitive() {
+        controller.apply {
+            registerDumpable("cb1", callback1)
+            registerDumpable("cb2", callback2)
+            registerDumpable("cb3", callback3)
+        }
+
+        val args = arrayOf("dependency", "DumpController", "CB3")
+        controller.dump(fd, pw, args)
+
+        verify(callback1, never()).dump(fd, pw, args)
+        verify(callback2, never()).dump(fd, pw, args)
+        verify(callback3 /* only once */).dump(fd, pw, args)
+    }
+
+    @Test
+    fun testFiltersAreIgnoredIfPrecedingArgsDontMatch() {
+        controller.apply {
+            registerDumpable("cb1", callback1)
+            registerDumpable("cb2", callback2)
+            registerDumpable("cb3", callback3)
+        }
+
+        val args = arrayOf("", "", "cb2")
+        controller.dump(fd, pw, args)
+
+        verify(callback1 /* only once */).dump(fd, pw, args)
+        verify(callback2 /* only once */).dump(fd, pw, args)
+        verify(callback3 /* only once */).dump(fd, pw, args)
+    }
+
+    @Test
     fun testRemoveListener() {
         controller.apply {
-            addListener(callback1)
-            addListener(callback2)
-            removeListener(callback1)
+            registerDumpable("cb1", callback1)
+            registerDumpable("cb2", callback2)
+            unregisterDumpable(callback1)
         }
 
         controller.dump(fd, pw, args)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index b3f6f4e..2221915 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -60,6 +60,7 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
@@ -67,6 +68,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -105,6 +107,10 @@
     private ZenModeController mZenModeController;
     @Mock
     private ZenModeConfig mZenModeConfig;
+    @Mock
+    private SysuiStatusBarStateController mStatusBarStateController;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
 
     private FrameLayout mStatusBarView;
     @Captor
@@ -143,7 +149,8 @@
 
         // Bubbles get added to status bar window view
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters);
+                mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.add(mStatusBarView, 120 /* height */);
 
         // Need notifications for bubbles
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 84a7d4f..1e1f2156 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -129,7 +129,7 @@
 
     @Test
     public void testShowImeButton() {
-        mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
+        mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true, false);
         waitForIdleSync();
         verify(mCallbacks).setImeWindowStatus(
                 eq(DEFAULT_DISPLAY), eq(null), eq(1), eq(2), eq(true));
@@ -137,7 +137,7 @@
 
     @Test
     public void testShowImeButtonForSecondaryDisplay() {
-        mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true);
+        mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true, false);
         waitForIdleSync();
         verify(mCallbacks).setImeWindowStatus(
                 eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
index 6ca5d2c..d804b6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
@@ -29,9 +29,12 @@
 import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -51,12 +54,17 @@
             = mock(NotificationLockscreenUserManager.class);
     private DynamicPrivacyController.Listener mListener
             = mock(DynamicPrivacyController.Listener.class);
+    private KeyguardMonitor mKeyguardMonitor = mock(KeyguardMonitor.class);
 
     @Before
     public void setUp() throws Exception {
         when(mCache.canSkipBouncer()).thenReturn(false);
+        when(mKeyguardMonitor.isShowing()).thenReturn(true);
         mDynamicPrivacyController = new DynamicPrivacyController(
-                mLockScreenUserManager, mCache);
+                mLockScreenUserManager, mKeyguardMonitor, mCache,
+                mock(StatusBarStateController.class));
+        mDynamicPrivacyController.setStatusBarKeyguardViewManager(
+                mock(StatusBarKeyguardViewManager.class));
         mDynamicPrivacyController.addListener(mListener);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index c1911ee..31054260 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -62,6 +62,7 @@
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
@@ -105,7 +106,7 @@
 
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
     @Mock private StatusBar mBar;
-    @Mock private StatusBarStateController mBarState;
+    @Mock private SysuiStatusBarStateController mBarState;
     @Mock private HeadsUpManagerPhone mHeadsUpManager;
     @Mock private NotificationBlockingHelperManager mBlockingHelperManager;
     @Mock private NotificationGroupManager mGroupManager;
@@ -136,7 +137,7 @@
         mDependency.injectTestDependency(
                 NotificationBlockingHelperManager.class,
                 mBlockingHelperManager);
-        mDependency.injectTestDependency(StatusBarStateController.class, mBarState);
+        mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState);
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
         mDependency.injectTestDependency(NotificationRemoteInputManager.class,
                 mRemoteInputManager);
@@ -162,7 +163,7 @@
                 mock(DynamicPrivacyController.class),
                 mock(ConfigurationController.class),
                 mock(ActivityStarterDelegate.class),
-                mock(StatusBarStateController.class),
+                mock(SysuiStatusBarStateController.class),
                 mHeadsUpManager,
                 mKeyguardBypassController,
                 new FalsingManagerFake());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 3da9a4b..db8af39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -183,7 +183,7 @@
 
         // Set IME window status for default NavBar.
         mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
-                BACK_DISPOSITION_DEFAULT, true);
+                BACK_DISPOSITION_DEFAULT, true, false);
         Handler.getMain().runWithScissors(() -> { }, 500);
 
         // Verify IME window state will be updated in default NavBar & external NavBar state reset.
@@ -194,7 +194,7 @@
 
         // Set IME window status for external NavBar.
         mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null,
-                IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true);
+                IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true, false);
         Handler.getMain().runWithScissors(() -> { }, 500);
 
         // Verify IME window state will be updated in external NavBar & default NavBar state reset.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index e811e1d..186a8c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -40,6 +40,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
@@ -75,7 +76,7 @@
                 mock(NotificationPanelView.class), mock(HeadsUpManagerPhone.class),
                 statusBarWindowView, mock(NotificationListContainerViewGroup.class),
                 mock(DozeScrimController.class), mock(ScrimController.class),
-                mock(ActivityLaunchAnimator.class), mock(StatusBarKeyguardViewManager.class),
+                mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
                 mock(NotificationAlertingManager.class),
                 mock(NotificationRowBinderImpl.class));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index cffd57b..fa235bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -157,7 +157,7 @@
     @Mock private RemoteInputController mRemoteInputController;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
-    @Mock private NotificationPresenter mNotificationPresenter;
+    @Mock private StatusBarNotificationPresenter mNotificationPresenter;
     @Mock
     private NotificationEntryListener mEntryListener;
     @Mock
@@ -780,7 +780,7 @@
                 NotificationShelf notificationShelf,
                 NotificationLockscreenUserManager notificationLockscreenUserManager,
                 CommandQueue commandQueue,
-                NotificationPresenter notificationPresenter,
+                StatusBarNotificationPresenter notificationPresenter,
                 BubbleController bubbleController,
                 NavigationBarController navBarController,
                 AutoHideController autoHideController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
index fea41a4..4ffaeae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
@@ -33,6 +33,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -54,6 +56,12 @@
     private ViewGroup mStatusBarView;
     @Mock
     private IActivityManager mActivityManager;
+    @Mock
+    private SysuiStatusBarStateController mStatusBarStateController;
+    @Mock
+    private ConfigurationController mConfigurationController;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
 
     private StatusBarWindowController mStatusBarWindowController;
 
@@ -63,7 +71,8 @@
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
 
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters);
+                mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.add(mStatusBarView, 100 /* height */);
     }
 
@@ -88,7 +97,8 @@
     @Test
     public void testOnThemeChanged_doesntCrash() {
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters);
+                mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.onThemeChanged();
     }
 
@@ -100,7 +110,8 @@
     @Test
     public void testSetForcePluginOpen_beforeStatusBarInitialization() {
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters);
+                mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.setForcePluginOpen(true);
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index d923bed..6b88f5a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -398,7 +398,8 @@
             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
                 return null;
             }
-            AccessibilityWindowInfo window = mA11yWindowManager.findA11yWindowInfoById(windowId);
+            AccessibilityWindowInfo window =
+                    mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId);
             if (window != null) {
                 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
                 windowClone.setConnectionId(mId);
@@ -1362,11 +1363,11 @@
                     || (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS);
             if (!isA11yFocusAction) {
                 final WindowInfo windowInfo =
-                        mA11yWindowManager.findWindowInfoById(resolvedWindowId);
+                        mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId);
                 if (windowInfo != null) activityToken = windowInfo.activityToken;
             }
             final AccessibilityWindowInfo a11yWindowInfo =
-                    mA11yWindowManager.findA11yWindowInfoById(resolvedWindowId);
+                    mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId);
             if (a11yWindowInfo != null && a11yWindowInfo.isInPictureInPictureMode()
                     && mA11yWindowManager.getPictureInPictureActionReplacingConnection() != null
                     && !isA11yFocusAction) {
@@ -1419,11 +1420,13 @@
             int interactionId, int interrogatingPid, long interrogatingTid) {
         final RemoteAccessibilityConnection pipActionReplacingConnection =
                 mA11yWindowManager.getPictureInPictureActionReplacingConnection();
-        final AccessibilityWindowInfo windowInfo =
-                mA11yWindowManager.findA11yWindowInfoById(resolvedWindowId);
-        if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode()
+        synchronized (mLock) {
+            final AccessibilityWindowInfo windowInfo =
+                    mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId);
+            if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode()
                 || (pipActionReplacingConnection == null)) {
-            return originalCallback;
+                return originalCallback;
+            }
         }
         return new ActionReplacingCallback(originalCallback,
                 pipActionReplacingConnection.getRemote(), interactionId,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 5111bec..18b6f90 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -29,6 +29,7 @@
 import android.view.MotionEvent;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.server.accessibility.gestures.TouchExplorer;
 import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy;
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8148536..b5b3cd2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -542,7 +542,7 @@
             if (event.getWindowId() ==
                 AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID) {
                 // The replacer window isn't shown to services. Move its events into the pip.
-                AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindow();
+                AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindowLocked();
                 if (pip != null) {
                     int pipId = pip.getId();
                     event.setWindowId(pipId);
@@ -771,7 +771,7 @@
             if (resolvedUserId != mCurrentUserId) {
                 return null;
             }
-            if (mA11yWindowManager.findA11yWindowInfoById(windowId) == null) {
+            if (mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId) == null) {
                 return null;
             }
             return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, windowId);
@@ -816,7 +816,7 @@
     }
 
 
-    boolean onGesture(AccessibilityGestureInfo gestureInfo) {
+    public boolean onGesture(AccessibilityGestureInfo gestureInfo) {
         synchronized (mLock) {
             boolean handled = notifyGestureLocked(gestureInfo, false);
             if (!handled) {
@@ -905,15 +905,15 @@
         return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action);
     }
 
-    int getActiveWindowId() {
+    public int getActiveWindowId() {
         return mA11yWindowManager.getActiveWindowId(mCurrentUserId);
     }
 
-    void onTouchInteractionStart() {
+    public void onTouchInteractionStart() {
         mA11yWindowManager.onTouchInteractionStart();
     }
 
-    void onTouchInteractionEnd() {
+    public void onTouchInteractionEnd() {
         mA11yWindowManager.onTouchInteractionEnd();
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index 1e224cf..315d6fa 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -429,7 +429,7 @@
         if (windowId == mAccessibilityWindowManager.getActiveWindowId(userId)) {
             return true;
         }
-        return mAccessibilityWindowManager.findA11yWindowInfoById(windowId) != null;
+        return mAccessibilityWindowManager.findA11yWindowInfoByIdLocked(windowId) != null;
     }
 
     private boolean isShellAllowedToRetrieveWindowLocked(int userId, int windowId) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 961168a..02f7821 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -361,7 +361,7 @@
                         mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
                 if (motionEventInjector != null && isTouchableDisplay) {
                     motionEventInjector.injectEvents(
-                            gestureSteps.getList(), mServiceInterface, sequence);
+                            gestureSteps.getList(), mServiceInterface, sequence, displayId);
                 } else {
                     try {
                         mServiceInterface.onPerformGestureResult(sequence, false);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index c129291..9687098 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -52,13 +52,10 @@
 import java.util.List;
 
 /**
- * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to receive
- * {@link WindowInfo}s from window manager when there's an accessibility change in window. It also
- * provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and
+ * This class provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and
  * {@link WindowInfo}s.
  */
-public class AccessibilityWindowManager
-        implements WindowManagerInternal.WindowsForAccessibilityCallback {
+public class AccessibilityWindowManager {
     private static final String LOG_TAG = "AccessibilityWindowManager";
     private static final boolean DEBUG = false;
 
@@ -71,9 +68,6 @@
     private final AccessibilitySecurityPolicy mSecurityPolicy;
     private final AccessibilityUserManager mAccessibilityUserManager;
 
-    private final SparseArray<AccessibilityWindowInfo> mA11yWindowInfoById = new SparseArray<>();
-    private final SparseArray<WindowInfo> mWindowInfoById = new SparseArray<>();
-
     // Connections and window tokens for cross-user windows
     private final SparseArray<RemoteAccessibilityConnection>
             mGlobalInteractionConnections = new SparseArray<>();
@@ -84,9 +78,6 @@
             mInteractionConnections = new SparseArray<>();
     private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>();
 
-    private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>();
-    private List<AccessibilityWindowInfo> mWindows;
-
     private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
 
     private int mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
@@ -95,15 +86,641 @@
     private long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
 
     private boolean mTouchInteractionInProgress;
-    private boolean mHasWatchOutsideTouchWindow;
-    private boolean mTrackingWindows = false;
 
+    // TO-DO [Multi-Display] : make DisplayWindowObserver to plural
+    private DisplayWindowsObserver mDisplayWindowsObserver;
+
+    /**
+     * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to
+     * receive {@link WindowInfo}s from window manager when there's an accessibility change in
+     * window and holds window lists information per display.
+     */
+    private final class DisplayWindowsObserver implements
+            WindowManagerInternal.WindowsForAccessibilityCallback {
+
+        private final int mDisplayId;
+        private final SparseArray<AccessibilityWindowInfo> mA11yWindowInfoById =
+                new SparseArray<>();
+        private final SparseArray<WindowInfo> mWindowInfoById = new SparseArray<>();
+        private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>();
+        private List<AccessibilityWindowInfo> mWindows;
+        private boolean mTrackingWindows = false;
+        private boolean mHasWatchOutsideTouchWindow;
+
+        /**
+         * Constructor for DisplayWindowsObserver.
+         */
+        DisplayWindowsObserver(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        /**
+         * Starts tracking windows changes from window manager by registering callback.
+         *
+         * @return true if callback registers successful.
+         */
+        boolean startTrackingWindowsLocked() {
+            boolean result = true;
+
+            if (!mTrackingWindows) {
+                // Turns on the flag before setup the callback.
+                // In some cases, onWindowsForAccessibilityChanged will be called immediately in
+                // setWindowsForAccessibilityCallback. We'll lost windows if flag is false.
+                mTrackingWindows = true;
+                result = mWindowManagerInternal.setWindowsForAccessibilityCallback(
+                        mDisplayId, this);
+                if (!result) {
+                    mTrackingWindows = false;
+                    Slog.w(LOG_TAG, "set windowsObserver callbacks fail, displayId:"
+                            + mDisplayId);
+                }
+            }
+            return result;
+        }
+
+        /**
+         * Stops tracking windows changes from window manager, and clear all windows info.
+         */
+        void stopTrackingWindowsLocked() {
+            if (mTrackingWindows) {
+                mWindowManagerInternal.setWindowsForAccessibilityCallback(
+                        mDisplayId, null);
+                mTrackingWindows = false;
+                clearWindowsLocked();
+            }
+        }
+
+        /**
+         * Returns true if windows changes tracking.
+         *
+         * @return true if windows changes tracking
+         */
+        boolean isTrackingWindowsLocked() {
+            return mTrackingWindows;
+        }
+
+        /**
+         * Returns accessibility windows.
+         * @return accessibility windows.
+         */
+        @Nullable
+        List<AccessibilityWindowInfo> getWindowListLocked() {
+            return mWindows;
+        }
+
+        /**
+         * Returns accessibility window info according to given windowId.
+         *
+         * @param windowId The windowId
+         * @return The accessibility window info
+         */
+        @Nullable
+        AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) {
+            return mA11yWindowInfoById.get(windowId);
+        }
+
+        /**
+         * Returns the window info according to given windowId.
+         *
+         * @param windowId The windowId
+         * @return The window info
+         */
+        @Nullable
+        WindowInfo findWindowInfoByIdLocked(int windowId) {
+            return mWindowInfoById.get(windowId);
+        }
+
+        /**
+         * Returns {@link AccessibilityWindowInfo} of PIP window.
+         *
+         * @return PIP accessibility window info
+         */
+        @Nullable
+        AccessibilityWindowInfo getPictureInPictureWindowLocked() {
+            if (mWindows != null) {
+                final int windowCount = mWindows.size();
+                for (int i = 0; i < windowCount; i++) {
+                    final AccessibilityWindowInfo window = mWindows.get(i);
+                    if (window.isInPictureInPictureMode()) {
+                        return window;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Sets the active flag of the window according to given windowId, others set to inactive.
+         *
+         * @param windowId The windowId
+         */
+        void setActiveWindowLocked(int windowId) {
+            if (mWindows != null) {
+                final int windowCount = mWindows.size();
+                for (int i = 0; i < windowCount; i++) {
+                    AccessibilityWindowInfo window = mWindows.get(i);
+                    if (window.getId() == windowId) {
+                        window.setActive(true);
+                        mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
+                                AccessibilityEvent.obtainWindowsChangedEvent(windowId,
+                                        AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
+                    } else {
+                        window.setActive(false);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Sets the window accessibility focused according to given windowId, others set
+         * unfocused.
+         *
+         * @param windowId The windowId
+         */
+        void setAccessibilityFocusedWindowLocked(int windowId) {
+            if (mWindows != null) {
+                final int windowCount = mWindows.size();
+                for (int i = 0; i < windowCount; i++) {
+                    AccessibilityWindowInfo window = mWindows.get(i);
+                    if (window.getId() == windowId) {
+                        window.setAccessibilityFocused(true);
+                        mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
+                                AccessibilityEvent.obtainWindowsChangedEvent(
+                                        windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
+
+                    } else {
+                        window.setAccessibilityFocused(false);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Computes partial interactive region of given windowId.
+         *
+         * @param windowId The windowId
+         * @param outRegion The output to which to write the bounds.
+         * @return true if outRegion is not empty.
+         */
+        boolean computePartialInteractiveRegionForWindowLocked(int windowId,
+                @NonNull Region outRegion) {
+            if (mWindows == null) {
+                return false;
+            }
+
+            // Windows are ordered in z order so start from the bottom and find
+            // the window of interest. After that all windows that cover it should
+            // be subtracted from the resulting region. Note that for accessibility
+            // we are returning only interactive windows.
+            Region windowInteractiveRegion = null;
+            boolean windowInteractiveRegionChanged = false;
+
+            final int windowCount = mWindows.size();
+            final Region currentWindowRegions = new Region();
+            for (int i = windowCount - 1; i >= 0; i--) {
+                AccessibilityWindowInfo currentWindow = mWindows.get(i);
+                if (windowInteractiveRegion == null) {
+                    if (currentWindow.getId() == windowId) {
+                        currentWindow.getRegionInScreen(currentWindowRegions);
+                        outRegion.set(currentWindowRegions);
+                        windowInteractiveRegion = outRegion;
+                        continue;
+                    }
+                } else if (currentWindow.getType()
+                        != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) {
+                    currentWindow.getRegionInScreen(currentWindowRegions);
+                    if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) {
+                        windowInteractiveRegionChanged = true;
+                    }
+                }
+            }
+
+            return windowInteractiveRegionChanged;
+        }
+
+        List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) {
+            final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
+            if (targetWindow != null && mHasWatchOutsideTouchWindow) {
+                final List<Integer> outsideWindowsId = new ArrayList<>();
+                for (int i = 0; i < mWindowInfoById.size(); i++) {
+                    final WindowInfo window = mWindowInfoById.valueAt(i);
+                    if (window != null && window.layer < targetWindow.layer
+                            && window.hasFlagWatchOutsideTouch) {
+                        outsideWindowsId.add(mWindowInfoById.keyAt(i));
+                    }
+                }
+                return outsideWindowsId;
+            }
+            return Collections.emptyList();
+        }
+
+        /**
+         * Callbacks from window manager when there's an accessibility change in windows.
+         *
+         * @param forceSend Send the windows for accessibility even if they haven't changed.
+         * @param windows The windows for accessibility.
+         */
+        @Override
+        public void onWindowsForAccessibilityChanged(boolean forceSend,
+                @NonNull List<WindowInfo> windows) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.i(LOG_TAG, "Display Id = " + mDisplayId);
+                    Slog.i(LOG_TAG, "Windows changed: " + windows);
+                }
+                if (shouldUpdateWindowsLocked(forceSend, windows)) {
+                    cacheWindows(windows);
+                    // Lets the policy update the focused and active windows.
+                    updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(),
+                            windows);
+                    // Someone may be waiting for the windows - advertise it.
+                    mLock.notifyAll();
+                }
+            }
+        }
+
+        private boolean shouldUpdateWindowsLocked(boolean forceSend,
+                @NonNull List<WindowInfo> windows) {
+            if (forceSend) {
+                return true;
+            }
+
+            final int windowCount = windows.size();
+            // We computed the windows and if they changed notify the client.
+            if (mCachedWindowInfos.size() != windowCount) {
+                // Different size means something changed.
+                return true;
+            } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) {
+                // Since we always traverse windows from high to low layer
+                // the old and new windows at the same index should be the
+                // same, otherwise something changed.
+                for (int i = 0; i < windowCount; i++) {
+                    WindowInfo oldWindow = mCachedWindowInfos.get(i);
+                    WindowInfo newWindow = windows.get(i);
+                    // We do not care for layer changes given the window
+                    // order does not change. This brings no new information
+                    // to the clients.
+                    if (windowChangedNoLayer(oldWindow, newWindow)) {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        private void cacheWindows(List<WindowInfo> windows) {
+            final int oldWindowCount = mCachedWindowInfos.size();
+            for (int i = oldWindowCount - 1; i >= 0; i--) {
+                mCachedWindowInfos.remove(i).recycle();
+            }
+            final int newWindowCount = windows.size();
+            for (int i = 0; i < newWindowCount; i++) {
+                WindowInfo newWindow = windows.get(i);
+                mCachedWindowInfos.add(WindowInfo.obtain(newWindow));
+            }
+        }
+
+        private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
+            if (oldWindow == newWindow) {
+                return false;
+            }
+            if (oldWindow == null) {
+                return true;
+            }
+            if (newWindow == null) {
+                return true;
+            }
+            if (oldWindow.type != newWindow.type) {
+                return true;
+            }
+            if (oldWindow.focused != newWindow.focused) {
+                return true;
+            }
+            if (oldWindow.token == null) {
+                if (newWindow.token != null) {
+                    return true;
+                }
+            } else if (!oldWindow.token.equals(newWindow.token)) {
+                return true;
+            }
+            if (oldWindow.parentToken == null) {
+                if (newWindow.parentToken != null) {
+                    return true;
+                }
+            } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
+                return true;
+            }
+            if (oldWindow.activityToken == null) {
+                if (newWindow.activityToken != null) {
+                    return true;
+                }
+            } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) {
+                return true;
+            }
+            if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) {
+                return true;
+            }
+            if (oldWindow.childTokens != null && newWindow.childTokens != null
+                    && !oldWindow.childTokens.equals(newWindow.childTokens)) {
+                return true;
+            }
+            if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
+                return true;
+            }
+            if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
+                return true;
+            }
+            if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) {
+                return true;
+            }
+            if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) {
+                return true;
+            }
+            if (oldWindow.displayId != newWindow.displayId) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Clears all {@link AccessibilityWindowInfo}s and {@link WindowInfo}s.
+         */
+        private void clearWindowsLocked() {
+            final List<WindowInfo> windows = Collections.emptyList();
+            final int activeWindowId = mActiveWindowId;
+            // UserId is useless in updateWindowsLocked, when we update a empty window list.
+            // Just pass current userId here.
+            updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);
+            // Do not reset mActiveWindowId here. mActiveWindowId will be clear after accessibility
+            // interaction connection removed.
+            mActiveWindowId = activeWindowId;
+            mWindows = null;
+        }
+
+        /**
+         * Updates windows info according to specified userId and windows.
+         *
+         * @param userId The userId to update
+         * @param windows The windows to update
+         */
+        private void updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows) {
+            if (mWindows == null) {
+                mWindows = new ArrayList<>();
+            }
+
+            final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows);
+            final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone();
+
+            mWindows.clear();
+            mA11yWindowInfoById.clear();
+
+            for (int i = 0; i < mWindowInfoById.size(); i++) {
+                mWindowInfoById.valueAt(i).recycle();
+            }
+            mWindowInfoById.clear();
+            mHasWatchOutsideTouchWindow = false;
+            mFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+            if (!mTouchInteractionInProgress) {
+                mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+            }
+
+            // If the active window goes away while the user is touch exploring we
+            // reset the active window id and wait for the next hover event from
+            // under the user's finger to determine which one is the new one. It
+            // is possible that the finger is not moving and the input system
+            // filters out such events.
+            boolean activeWindowGone = true;
+
+            final int windowCount = windows.size();
+
+            // We'll clear accessibility focus if the window with focus is no longer visible to
+            // accessibility services
+            boolean shouldClearAccessibilityFocus =
+                    mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+            if (windowCount > 0) {
+                for (int i = 0; i < windowCount; i++) {
+                    final WindowInfo windowInfo = windows.get(i);
+                    final AccessibilityWindowInfo window;
+                    if (isTrackingWindowsLocked()) {
+                        window = populateReportedWindowLocked(userId, windowInfo);
+                    } else {
+                        window = null;
+                    }
+                    if (window != null) {
+
+                        // Flip layers in list to be consistent with AccessibilityService#getWindows
+                        window.setLayer(windowCount - 1 - window.getLayer());
+
+                        final int windowId = window.getId();
+                        if (window.isFocused()) {
+                            mFocusedWindowId = windowId;
+                            if (!mTouchInteractionInProgress) {
+                                mActiveWindowId = windowId;
+                                window.setActive(true);
+                            } else if (windowId == mActiveWindowId) {
+                                activeWindowGone = false;
+                            }
+                        }
+                        if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) {
+                            mHasWatchOutsideTouchWindow = true;
+                        }
+                        mWindows.add(window);
+                        mA11yWindowInfoById.put(windowId, window);
+                        mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo));
+                    }
+                }
+
+                if (mTouchInteractionInProgress && activeWindowGone) {
+                    mActiveWindowId = mFocusedWindowId;
+                }
+
+                // Focused window may change the active one, so set the
+                // active window once we decided which it is.
+                final int accessibilityWindowCount = mWindows.size();
+                for (int i = 0; i < accessibilityWindowCount; i++) {
+                    final AccessibilityWindowInfo window = mWindows.get(i);
+                    if (window.getId() == mActiveWindowId) {
+                        window.setActive(true);
+                    }
+                    if (window.getId() == mAccessibilityFocusedWindowId) {
+                        window.setAccessibilityFocused(true);
+                        shouldClearAccessibilityFocus = false;
+                    }
+                }
+            }
+
+            sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById);
+
+            final int oldWindowCount = oldWindowList.size();
+            for (int i = oldWindowCount - 1; i >= 0; i--) {
+                oldWindowList.remove(i).recycle();
+            }
+
+            if (shouldClearAccessibilityFocus) {
+                clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId);
+            }
+        }
+
+        private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows,
+                SparseArray<AccessibilityWindowInfo> oldWindowsById) {
+            List<AccessibilityEvent> events = new ArrayList<>();
+            // Sends events for all removed windows.
+            final int oldWindowsCount = oldWindows.size();
+            for (int i = 0; i < oldWindowsCount; i++) {
+                final AccessibilityWindowInfo window = oldWindows.get(i);
+                if (mA11yWindowInfoById.get(window.getId()) == null) {
+                    events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+                            window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED));
+                }
+            }
+
+            // Looks for other changes.
+            final int newWindowCount = mWindows.size();
+            for (int i = 0; i < newWindowCount; i++) {
+                final AccessibilityWindowInfo newWindow = mWindows.get(i);
+                final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId());
+                if (oldWindow == null) {
+                    events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+                            newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED));
+                } else {
+                    int changes = newWindow.differenceFrom(oldWindow);
+                    if (changes !=  0) {
+                        events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+                                newWindow.getId(), changes));
+                    }
+                }
+            }
+
+            final int numEvents = events.size();
+            for (int i = 0; i < numEvents; i++) {
+                mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(events.get(i));
+            }
+        }
+
+        private AccessibilityWindowInfo populateReportedWindowLocked(int userId,
+                WindowInfo window) {
+            final int windowId = findWindowIdLocked(userId, window.token);
+            if (windowId < 0) {
+                return null;
+            }
+
+            final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
+
+            reportedWindow.setId(windowId);
+            reportedWindow.setType(getTypeForWindowManagerWindowType(window.type));
+            reportedWindow.setLayer(window.layer);
+            reportedWindow.setFocused(window.focused);
+            reportedWindow.setRegionInScreen(window.regionInScreen);
+            reportedWindow.setTitle(window.title);
+            reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
+            reportedWindow.setPictureInPicture(window.inPictureInPicture);
+            reportedWindow.setDisplayId(window.displayId);
+
+            final int parentId = findWindowIdLocked(userId, window.parentToken);
+            if (parentId >= 0) {
+                reportedWindow.setParentId(parentId);
+            }
+
+            if (window.childTokens != null) {
+                final int childCount = window.childTokens.size();
+                for (int i = 0; i < childCount; i++) {
+                    final IBinder childToken = window.childTokens.get(i);
+                    final int childId = findWindowIdLocked(userId, childToken);
+                    if (childId >= 0) {
+                        reportedWindow.addChild(childId);
+                    }
+                }
+            }
+
+            return reportedWindow;
+        }
+
+        private int getTypeForWindowManagerWindowType(int windowType) {
+            switch (windowType) {
+                case WindowManager.LayoutParams.TYPE_APPLICATION:
+                case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
+                case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
+                case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING:
+                case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
+                case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
+                case WindowManager.LayoutParams.TYPE_BASE_APPLICATION:
+                case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
+                case WindowManager.LayoutParams.TYPE_PHONE:
+                case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
+                case WindowManager.LayoutParams.TYPE_TOAST:
+                case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: {
+                    return AccessibilityWindowInfo.TYPE_APPLICATION;
+                }
+
+                case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
+                case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: {
+                    return AccessibilityWindowInfo.TYPE_INPUT_METHOD;
+                }
+
+                case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
+                case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
+                case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
+                case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
+                case WindowManager.LayoutParams.TYPE_STATUS_BAR:
+                case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL:
+                case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL:
+                case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
+                case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
+                case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
+                case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
+                case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+                case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
+                case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
+                    return AccessibilityWindowInfo.TYPE_SYSTEM;
+                }
+
+                case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
+                    return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER;
+                }
+
+                case TYPE_ACCESSIBILITY_OVERLAY: {
+                    return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
+                }
+
+                default: {
+                    return -1;
+                }
+            }
+        }
+
+        /**
+         * Dumps all {@link AccessibilityWindowInfo}s here.
+         */
+        void dumpLocked(FileDescriptor fd, final PrintWriter pw, String[] args) {
+            if (mWindows != null) {
+                final int windowCount = mWindows.size();
+                for (int j = 0; j < windowCount; j++) {
+                    if (j == 0) {
+                        pw.append("Display[");
+                        pw.append(Integer.toString(mDisplayId));
+                        pw.append("] : ");
+                        pw.println();
+                    }
+                    if (j > 0) {
+                        pw.append(',');
+                        pw.println();
+                    }
+                    pw.append("Window[");
+                    AccessibilityWindowInfo window = mWindows.get(j);
+                    pw.append(window.toString());
+                    pw.append(']');
+                }
+                pw.println();
+            }
+        }
+    }
     /**
      * Interface to send {@link AccessibilityEvent}.
      */
     public interface AccessibilityEventSender {
         /**
-         * Send {@link AccessibilityEvent} for current user.
+         * Sends {@link AccessibilityEvent} for current user.
          */
         void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event);
     }
@@ -171,166 +788,24 @@
         mAccessibilityEventSender = accessibilityEventSender;
         mSecurityPolicy = securityPolicy;
         mAccessibilityUserManager = accessibilityUserManager;
-
+        mDisplayWindowsObserver = new DisplayWindowsObserver(Display.DEFAULT_DISPLAY);
     }
 
     /**
-     * Callbacks from window manager when there's an accessibility change in windows.
-     *
-     * @param forceSend Send the windows for accessibility even if they haven't changed.
-     * @param windows The windows of current display for accessibility.
-     */
-    @Override
-    public void onWindowsForAccessibilityChanged(boolean forceSend,
-            @NonNull List<WindowInfo> windows) {
-        synchronized (mLock) {
-            if (DEBUG) {
-                Slog.i(LOG_TAG, "Windows changed: " + windows);
-            }
-
-            if (shouldUpdateWindowsLocked(forceSend, windows)) {
-                cacheWindows(windows);
-                // Let the policy update the focused and active windows.
-                updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);
-                // Someone may be waiting for the windows - advertise it.
-                mLock.notifyAll();
-            }
-        }
-    }
-
-    private boolean shouldUpdateWindowsLocked(boolean forceSend,
-            @NonNull List<WindowInfo> windows) {
-        if (forceSend) {
-            return true;
-        }
-
-        final int windowCount = windows.size();
-        // We computed the windows and if they changed notify the client.
-        if (mCachedWindowInfos.size() != windowCount) {
-            // Different size means something changed.
-            return true;
-        } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) {
-            // Since we always traverse windows from high to low layer
-            // the old and new windows at the same index should be the
-            // same, otherwise something changed.
-            for (int i = 0; i < windowCount; i++) {
-                WindowInfo oldWindow = mCachedWindowInfos.get(i);
-                WindowInfo newWindow = windows.get(i);
-                // We do not care for layer changes given the window
-                // order does not change. This brings no new information
-                // to the clients.
-                if (windowChangedNoLayer(oldWindow, newWindow)) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    private void cacheWindows(List<WindowInfo> windows) {
-        final int oldWindowCount = mCachedWindowInfos.size();
-        for (int i = oldWindowCount - 1; i >= 0; i--) {
-            mCachedWindowInfos.remove(i).recycle();
-        }
-        final int newWindowCount = windows.size();
-        for (int i = 0; i < newWindowCount; i++) {
-            WindowInfo newWindow = windows.get(i);
-            mCachedWindowInfos.add(WindowInfo.obtain(newWindow));
-        }
-    }
-
-    private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
-        if (oldWindow == newWindow) {
-            return false;
-        }
-        if (oldWindow == null) {
-            return true;
-        }
-        if (newWindow == null) {
-            return true;
-        }
-        if (oldWindow.type != newWindow.type) {
-            return true;
-        }
-        if (oldWindow.focused != newWindow.focused) {
-            return true;
-        }
-        if (oldWindow.token == null) {
-            if (newWindow.token != null) {
-                return true;
-            }
-        } else if (!oldWindow.token.equals(newWindow.token)) {
-            return true;
-        }
-        if (oldWindow.parentToken == null) {
-            if (newWindow.parentToken != null) {
-                return true;
-            }
-        } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
-            return true;
-        }
-        if (oldWindow.activityToken == null) {
-            if (newWindow.activityToken != null) {
-                return true;
-            }
-        } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) {
-            return true;
-        }
-        if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) {
-            return true;
-        }
-        if (oldWindow.childTokens != null && newWindow.childTokens != null
-                && !oldWindow.childTokens.equals(newWindow.childTokens)) {
-            return true;
-        }
-        if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
-            return true;
-        }
-        if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
-            return true;
-        }
-        if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) {
-            return true;
-        }
-        if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) {
-            return true;
-        }
-        if (oldWindow.displayId != newWindow.displayId) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Start tracking windows changes from window manager.
+     * Starts tracking windows changes from window manager.
      */
     public void startTrackingWindows() {
         synchronized (mLock) {
-            if (!mTrackingWindows) {
-                // Turn on the flag before setup the callback.
-                // In some cases, onWindowsForAccessibilityChanged will be called immediately in
-                // setWindowsForAccessibilityCallback. We'll lost windows if flag is false.
-                mTrackingWindows = true;
-                // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
-                mWindowManagerInternal.setWindowsForAccessibilityCallback(Display.DEFAULT_DISPLAY,
-                        this);
-            }
+            mDisplayWindowsObserver.startTrackingWindowsLocked();
         }
     }
 
     /**
-     * stop tracking windows changes from window manager, and clear all windows info.
+     * Stops tracking windows changes from window manager, and clear all windows info.
      */
     public void stopTrackingWindows() {
         synchronized (mLock) {
-            if (mTrackingWindows) {
-                // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
-                mWindowManagerInternal.setWindowsForAccessibilityCallback(Display.DEFAULT_DISPLAY,
-                        null);
-                mTrackingWindows = false;
-                clearWindowsLocked();
-            }
+            mDisplayWindowsObserver.stopTrackingWindowsLocked();
         }
     }
 
@@ -340,127 +815,7 @@
      * @return true if windows changes tracking
      */
     public boolean isTrackingWindowsLocked() {
-        return mTrackingWindows;
-    }
-
-    /**
-     * Clears all {@link AccessibilityWindowInfo}s and {@link WindowInfo}s.
-     */
-    private void clearWindowsLocked() {
-        final List<WindowInfo> windows = Collections.emptyList();
-        final int activeWindowId = mActiveWindowId;
-        // userId is useless in updateWindowsLocked, when we update a empty window list. Just pass
-        // current userId here.
-        updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);
-        // Do not reset mActiveWindowId here. mActiveWindowId will be clear after accessibility
-        // interaction connection removed.
-        mActiveWindowId = activeWindowId;
-        mWindows = null;
-    }
-
-    /**
-     * Update windows info according to specified userId and windows.
-     *
-     * @param userId The userId to update
-     * @param windows The windows to update
-     */
-    private void updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows) {
-        if (mWindows == null) {
-            mWindows = new ArrayList<>();
-        }
-
-        final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows);
-        final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone();
-
-        mWindows.clear();
-        mA11yWindowInfoById.clear();
-
-        for (int i = 0; i < mWindowInfoById.size(); i++) {
-            mWindowInfoById.valueAt(i).recycle();
-        }
-        mWindowInfoById.clear();
-        mHasWatchOutsideTouchWindow = false;
-
-        mFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
-        if (!mTouchInteractionInProgress) {
-            mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
-        }
-
-        // If the active window goes away while the user is touch exploring we
-        // reset the active window id and wait for the next hover event from
-        // under the user's finger to determine which one is the new one. It
-        // is possible that the finger is not moving and the input system
-        // filters out such events.
-        boolean activeWindowGone = true;
-
-        final int windowCount = windows.size();
-
-        // We'll clear accessibility focus if the window with focus is no longer visible to
-        // accessibility services
-        boolean shouldClearAccessibilityFocus =
-                mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
-        if (windowCount > 0) {
-            for (int i = 0; i < windowCount; i++) {
-                final WindowInfo windowInfo = windows.get(i);
-                final AccessibilityWindowInfo window;
-                if (isTrackingWindowsLocked()) {
-                    window = populateReportedWindowLocked(userId, windowInfo);
-                } else {
-                    window = null;
-                }
-                if (window != null) {
-
-                    // Flip layers in list to be consistent with AccessibilityService#getWindows
-                    window.setLayer(windowCount - 1 - window.getLayer());
-
-                    final int windowId = window.getId();
-                    if (window.isFocused()) {
-                        mFocusedWindowId = windowId;
-                        if (!mTouchInteractionInProgress) {
-                            mActiveWindowId = windowId;
-                            window.setActive(true);
-                        } else if (windowId == mActiveWindowId) {
-                            activeWindowGone = false;
-                        }
-                    }
-                    if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) {
-                        mHasWatchOutsideTouchWindow = true;
-                    }
-                    mWindows.add(window);
-                    mA11yWindowInfoById.put(windowId, window);
-                    mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo));
-                }
-            }
-
-            if (mTouchInteractionInProgress && activeWindowGone) {
-                mActiveWindowId = mFocusedWindowId;
-            }
-
-            // Focused window may change the active one, so set the
-            // active window once we decided which it is.
-            final int accessibilityWindowCount = mWindows.size();
-            for (int i = 0; i < accessibilityWindowCount; i++) {
-                final AccessibilityWindowInfo window = mWindows.get(i);
-                if (window.getId() == mActiveWindowId) {
-                    window.setActive(true);
-                }
-                if (window.getId() == mAccessibilityFocusedWindowId) {
-                    window.setAccessibilityFocused(true);
-                    shouldClearAccessibilityFocus = false;
-                }
-            }
-        }
-
-        sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById);
-
-        final int oldWindowCount = oldWindowList.size();
-        for (int i = oldWindowCount - 1; i >= 0; i--) {
-            oldWindowList.remove(i).recycle();
-        }
-
-        if (shouldClearAccessibilityFocus) {
-            clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId);
-        }
+        return mDisplayWindowsObserver.isTrackingWindowsLocked();
     }
 
     /**
@@ -468,7 +823,7 @@
      */
     @Nullable
     public List<AccessibilityWindowInfo> getWindowListLocked() {
-        return mWindows;
+        return mDisplayWindowsObserver.getWindowListLocked();
     }
 
     /**
@@ -494,7 +849,7 @@
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId());
 
-            // Make sure the reported package is one the caller has access to.
+            // Makes sure the reported package is one the caller has access to.
             packageName = mSecurityPolicy.resolveValidReportedPackageLocked(
                     packageName, UserHandle.getCallingAppId(), resolvedUserId);
 
@@ -576,7 +931,7 @@
     }
 
     /**
-     * Resolve a connection wrapper for a window id
+     * Resolves a connection wrapper for a window id.
      *
      * @param userId The user id for any user-specific windows
      * @param windowId The id of the window of interest
@@ -672,7 +1027,7 @@
     }
 
     /**
-     * Return the userId that owns the given window token, {@link UserHandle#USER_NULL}
+     * Returns the userId that owns the given window token, {@link UserHandle#USER_NULL}
      * if not found.
      *
      * @param windowToken The winodw token
@@ -703,42 +1058,6 @@
         return -1;
     }
 
-    private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows,
-            SparseArray<AccessibilityWindowInfo> oldWindowsById) {
-        List<AccessibilityEvent> events = new ArrayList<>();
-        // Send events for all removed windows
-        final int oldWindowsCount = oldWindows.size();
-        for (int i = 0; i < oldWindowsCount; i++) {
-            final AccessibilityWindowInfo window = oldWindows.get(i);
-            if (mA11yWindowInfoById.get(window.getId()) == null) {
-                events.add(AccessibilityEvent.obtainWindowsChangedEvent(
-                        window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED));
-            }
-        }
-
-        // Look for other changes
-        final int newWindowCount = mWindows.size();
-        for (int i = 0; i < newWindowCount; i++) {
-            final AccessibilityWindowInfo newWindow = mWindows.get(i);
-            final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId());
-            if (oldWindow == null) {
-                events.add(AccessibilityEvent.obtainWindowsChangedEvent(
-                        newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED));
-            } else {
-                int changes = newWindow.differenceFrom(oldWindow);
-                if (changes !=  0) {
-                    events.add(AccessibilityEvent.obtainWindowsChangedEvent(
-                            newWindow.getId(), changes));
-                }
-            }
-        }
-
-        final int numEvents = events.size();
-        for (int i = 0; i < numEvents; i++) {
-            mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(events.get(i));
-        }
-    }
-
     /**
      * Computes partial interactive region of given windowId.
      *
@@ -748,38 +1067,8 @@
      */
     public boolean computePartialInteractiveRegionForWindowLocked(int windowId,
             @NonNull Region outRegion) {
-        if (mWindows == null) {
-            return false;
-        }
-
-        // Windows are ordered in z order so start from the bottom and find
-        // the window of interest. After that all windows that cover it should
-        // be subtracted from the resulting region. Note that for accessibility
-        // we are returning only interactive windows.
-        Region windowInteractiveRegion = null;
-        boolean windowInteractiveRegionChanged = false;
-
-        final int windowCount = mWindows.size();
-        final Region currentWindowRegions = new Region();
-        for (int i = windowCount - 1; i >= 0; i--) {
-            AccessibilityWindowInfo currentWindow = mWindows.get(i);
-            if (windowInteractiveRegion == null) {
-                if (currentWindow.getId() == windowId) {
-                    currentWindow.getRegionInScreen(currentWindowRegions);
-                    outRegion.set(currentWindowRegions);
-                    windowInteractiveRegion = outRegion;
-                    continue;
-                }
-            } else if (currentWindow.getType()
-                    != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) {
-                currentWindow.getRegionInScreen(currentWindowRegions);
-                if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) {
-                    windowInteractiveRegionChanged = true;
-                }
-            }
-        }
-
-        return windowInteractiveRegionChanged;
+        return mDisplayWindowsObserver.computePartialInteractiveRegionForWindowLocked(windowId,
+            outRegion);
     }
 
     /**
@@ -846,7 +1135,7 @@
                         mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
                     }
                     // Clear the window with focus if it no longer has focus and we aren't
-                    // just moving focus from one view to the other in the same window
+                    // just moving focus from one view to the other in the same window.
                     if ((mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)
                             && (mAccessibilityFocusedWindowId == windowId)
                             && (eventAction != AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)) {
@@ -904,7 +1193,7 @@
     }
 
     /**
-     * Get the id of the current active window.
+     * Gets the id of the current active window.
      *
      * @return The userId
      */
@@ -923,20 +1212,7 @@
                             mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
 
             mActiveWindowId = windowId;
-            if (mWindows != null) {
-                final int windowCount = mWindows.size();
-                for (int i = 0; i < windowCount; i++) {
-                    AccessibilityWindowInfo window = mWindows.get(i);
-                    if (window.getId() == windowId) {
-                        window.setActive(true);
-                        mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
-                                AccessibilityEvent.obtainWindowsChangedEvent(windowId,
-                                        AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
-                    } else {
-                        window.setActive(false);
-                    }
-                }
-            }
+            mDisplayWindowsObserver.setActiveWindowLocked(windowId);
         }
     }
 
@@ -948,21 +1224,7 @@
                             WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
 
             mAccessibilityFocusedWindowId = windowId;
-            if (mWindows != null) {
-                final int windowCount = mWindows.size();
-                for (int i = 0; i < windowCount; i++) {
-                    AccessibilityWindowInfo window = mWindows.get(i);
-                    if (window.getId() == windowId) {
-                        window.setAccessibilityFocused(true);
-                        mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
-                                AccessibilityEvent.obtainWindowsChangedEvent(
-                                        windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
-
-                    } else {
-                        window.setAccessibilityFocused(false);
-                    }
-                }
-            }
+            mDisplayWindowsObserver.setAccessibilityFocusedWindowLocked(windowId);
         }
     }
 
@@ -973,8 +1235,8 @@
      * @return The accessibility window info
      */
     @Nullable
-    public AccessibilityWindowInfo findA11yWindowInfoById(int windowId) {
-        return mA11yWindowInfoById.get(windowId);
+    public AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) {
+        return mDisplayWindowsObserver.findA11yWindowInfoByIdLocked(windowId);
     }
 
     /**
@@ -984,8 +1246,8 @@
      * @return The window info
      */
     @Nullable
-    public WindowInfo findWindowInfoById(int windowId) {
-        return mWindowInfoById.get(windowId);
+    public WindowInfo findWindowInfoByIdLocked(int windowId) {
+        return mDisplayWindowsObserver.findWindowInfoByIdLocked(windowId);
     }
 
     /**
@@ -1010,21 +1272,12 @@
      * @return PIP accessibility window info
      */
     @Nullable
-    public AccessibilityWindowInfo getPictureInPictureWindow() {
-        if (mWindows != null) {
-            final int windowCount = mWindows.size();
-            for (int i = 0; i < windowCount; i++) {
-                final AccessibilityWindowInfo window = mWindows.get(i);
-                if (window.isInPictureInPictureMode()) {
-                    return window;
-                }
-            }
-        }
-        return null;
+    public AccessibilityWindowInfo getPictureInPictureWindowLocked() {
+        return mDisplayWindowsObserver.getPictureInPictureWindowLocked();
     }
 
     /**
-     * Set an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture
+     * Sets an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture
      * window.
      */
     public void setPictureInPictureActionReplacingConnection(
@@ -1060,7 +1313,8 @@
         final List<Integer> outsideWindowsIds;
         final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>();
         synchronized (mLock) {
-            outsideWindowsIds = getWatchOutsideTouchWindowIdLocked(targetWindowId);
+            outsideWindowsIds =
+                mDisplayWindowsObserver.getWatchOutsideTouchWindowIdLocked(targetWindowId);
             for (int i = 0; i < outsideWindowsIds.size(); i++) {
                 connectionList.add(getConnectionLocked(userId, outsideWindowsIds.get(i)));
             }
@@ -1079,22 +1333,6 @@
         }
     }
 
-    private List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) {
-        final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
-        if (targetWindow != null && mHasWatchOutsideTouchWindow) {
-            final List<Integer> outsideWindowsId = new ArrayList<>();
-            for (int i = 0; i < mWindowInfoById.size(); i++) {
-                final WindowInfo window = mWindowInfoById.valueAt(i);
-                if (window != null && window.layer < targetWindow.layer
-                        && window.hasFlagWatchOutsideTouch) {
-                    outsideWindowsId.add(mWindowInfoById.keyAt(i));
-                }
-            }
-            return outsideWindowsId;
-        }
-        return Collections.emptyList();
-    }
-
     /**
      * Gets current input focused window token from window manager, and returns its windowId.
      *
@@ -1108,96 +1346,6 @@
         }
     }
 
-    private AccessibilityWindowInfo populateReportedWindowLocked(int userId, WindowInfo window) {
-        final int windowId = findWindowIdLocked(userId, window.token);
-        if (windowId < 0) {
-            return null;
-        }
-
-        final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
-
-        reportedWindow.setId(windowId);
-        reportedWindow.setType(getTypeForWindowManagerWindowType(window.type));
-        reportedWindow.setLayer(window.layer);
-        reportedWindow.setFocused(window.focused);
-        reportedWindow.setRegionInScreen(window.regionInScreen);
-        reportedWindow.setTitle(window.title);
-        reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
-        reportedWindow.setPictureInPicture(window.inPictureInPicture);
-        reportedWindow.setDisplayId(window.displayId);
-
-        final int parentId = findWindowIdLocked(userId, window.parentToken);
-        if (parentId >= 0) {
-            reportedWindow.setParentId(parentId);
-        }
-
-        if (window.childTokens != null) {
-            final int childCount = window.childTokens.size();
-            for (int i = 0; i < childCount; i++) {
-                final IBinder childToken = window.childTokens.get(i);
-                final int childId = findWindowIdLocked(userId, childToken);
-                if (childId >= 0) {
-                    reportedWindow.addChild(childId);
-                }
-            }
-        }
-
-        return reportedWindow;
-    }
-
-    private int getTypeForWindowManagerWindowType(int windowType) {
-        switch (windowType) {
-            case WindowManager.LayoutParams.TYPE_APPLICATION:
-            case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
-            case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
-            case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING:
-            case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
-            case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
-            case WindowManager.LayoutParams.TYPE_BASE_APPLICATION:
-            case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
-            case WindowManager.LayoutParams.TYPE_PHONE:
-            case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
-            case WindowManager.LayoutParams.TYPE_TOAST:
-            case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: {
-                return AccessibilityWindowInfo.TYPE_APPLICATION;
-            }
-
-            case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
-            case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: {
-                return AccessibilityWindowInfo.TYPE_INPUT_METHOD;
-            }
-
-            case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
-            case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
-            case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
-            case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
-            case WindowManager.LayoutParams.TYPE_STATUS_BAR:
-            case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL:
-            case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL:
-            case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
-            case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
-            case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
-            case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
-            case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
-            case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
-            case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
-                return AccessibilityWindowInfo.TYPE_SYSTEM;
-            }
-
-            case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
-                return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER;
-            }
-
-            case TYPE_ACCESSIBILITY_OVERLAY: {
-                return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
-            }
-
-            default: {
-                return -1;
-            }
-        }
-    }
-
     private boolean isValidUserForInteractionConnectionsLocked(int userId) {
         return mInteractionConnections.indexOfKey(userId) >= 0;
     }
@@ -1251,22 +1399,9 @@
     }
 
     /**
-     * Dump all {@link AccessibilityWindowInfo}s here.
+     * Dumps all {@link AccessibilityWindowInfo}s here.
      */
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
-        if (mWindows != null) {
-            final int windowCount = mWindows.size();
-            for (int j = 0; j < windowCount; j++) {
-                if (j > 0) {
-                    pw.append(',');
-                    pw.println();
-                }
-                pw.append("Window[");
-                AccessibilityWindowInfo window = mWindows.get(j);
-                pw.append(window.toString());
-                pw.append(']');
-            }
-            pw.println();
-        }
+        mDisplayWindowsObserver.dumpLocked(fd, pw, args);
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java
index ce54586..1645721 100644
--- a/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java
+++ b/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java
@@ -16,7 +16,7 @@
 
 package com.android.server.accessibility;
 
-abstract class BaseEventStreamTransformation implements EventStreamTransformation {
+public abstract class BaseEventStreamTransformation implements EventStreamTransformation {
     private EventStreamTransformation mNext;
 
     @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
index 7982996..61aff9a 100644
--- a/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
+++ b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
@@ -54,7 +54,7 @@
  * For example, if it received a down motion event followed by a cancel motion
  * event, it should not handle subsequent move and up events until it gets a down.
  */
-interface EventStreamTransformation {
+public interface EventStreamTransformation {
 
     /**
      * Receives a motion event. Passed are the event transformed by previous
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 1d58e90..06ca054 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -24,7 +24,7 @@
 import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
 
-import static com.android.server.accessibility.GestureUtils.distance;
+import static com.android.server.accessibility.gestures.GestureUtils.distance;
 
 import static java.lang.Math.abs;
 import static java.util.Arrays.asList;
@@ -54,6 +54,7 @@
 import android.view.ViewConfiguration;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.accessibility.gestures.GestureUtils;
 
 import java.util.ArrayDeque;
 import java.util.Queue;
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
index 7b6a128..3310cb4 100644
--- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -101,11 +101,12 @@
      * either complete or cancelled.
      */
     public void injectEvents(List<GestureStep> gestureSteps,
-            IAccessibilityServiceClient serviceInterface, int sequence) {
+            IAccessibilityServiceClient serviceInterface, int sequence, int displayId) {
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = gestureSteps;
         args.arg2 = serviceInterface;
         args.argi1 = sequence;
+        args.argi2 = displayId;
         mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args));
     }
 
@@ -146,7 +147,7 @@
         if (message.what == MESSAGE_INJECT_EVENTS) {
             SomeArgs args = (SomeArgs) message.obj;
             injectEventsMainThread((List<GestureStep>) args.arg1,
-                    (IAccessibilityServiceClient) args.arg2, args.argi1);
+                    (IAccessibilityServiceClient) args.arg2, args.argi1, args.argi2);
             args.recycle();
             return true;
         }
@@ -165,7 +166,7 @@
     }
 
     private void injectEventsMainThread(List<GestureStep> gestureSteps,
-            IAccessibilityServiceClient serviceInterface, int sequence) {
+            IAccessibilityServiceClient serviceInterface, int sequence, int displayId) {
         if (mIsDestroyed) {
             try {
                 serviceInterface.onPerformGestureResult(sequence, false);
@@ -209,6 +210,7 @@
 
         for (int i = 0; i < events.size(); i++) {
             MotionEvent event = events.get(i);
+            event.setDisplayId(displayId);
             int isEndOfSequence = (i == events.size() - 1) ? 1 : 0;
             Message message = mHandler.obtainMessage(
                     MESSAGE_SEND_MOTION_EVENT, isEndOfSequence, 0, event);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java
similarity index 99%
rename from services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
rename to services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java
index b4ac92f..9101a01 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java
@@ -14,7 +14,7 @@
  ** limitations under the License.
  */
 
-package com.android.server.accessibility;
+package com.android.server.accessibility.gestures;
 
 import android.accessibilityservice.AccessibilityGestureInfo;
 import android.accessibilityservice.AccessibilityService;
diff --git a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
similarity index 97%
rename from services/accessibility/java/com/android/server/accessibility/GestureUtils.java
rename to services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
index d5b53bc..0f5dd08 100644
--- a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
@@ -1,4 +1,4 @@
-package com.android.server.accessibility;
+package com.android.server.accessibility.gestures;
 
 import android.util.MathUtils;
 import android.view.MotionEvent;
@@ -6,7 +6,7 @@
 /**
  * Some helper functions for gesture detection.
  */
-final class GestureUtils {
+public final class GestureUtils {
 
     private GestureUtils() {
         /* cannot be instantiated */
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
similarity index 99%
rename from services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
rename to services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 380e853..10c32ee 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -14,11 +14,11 @@
  ** limitations under the License.
  */
 
-package com.android.server.accessibility;
+package com.android.server.accessibility.gestures;
 
 import static android.view.MotionEvent.INVALID_POINTER_ID;
 
-import static com.android.server.accessibility.TouchState.ALL_POINTER_ID_BITS;
+import static com.android.server.accessibility.gestures.TouchState.ALL_POINTER_ID_BITS;
 
 import android.accessibilityservice.AccessibilityGestureInfo;
 import android.content.Context;
@@ -34,6 +34,8 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accessibility.BaseEventStreamTransformation;
 import com.android.server.policy.WindowManagerPolicy;
 
 import java.util.ArrayList;
@@ -58,7 +60,7 @@
  *
  * @hide
  */
-class TouchExplorer extends BaseEventStreamTransformation
+public class TouchExplorer extends BaseEventStreamTransformation
         implements AccessibilityGestureDetector.Listener {
 
     private static final boolean DEBUG = false;
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
similarity index 99%
rename from services/accessibility/java/com/android/server/accessibility/TouchState.java
rename to services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index 7569b05..820c1a7 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.accessibility;
+package com.android.server.accessibility.gestures;
 
 import static android.view.MotionEvent.INVALID_POINTER_ID;
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4f7900e..293ab02 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5520,7 +5520,6 @@
         }
         nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
         NetworkInfo networkInfo = nai.networkInfo;
-        nai.networkInfo = null;
         updateNetworkInfo(nai, networkInfo);
         updateUids(nai, null, nai.networkCapabilities);
     }
@@ -6519,8 +6518,7 @@
 
         if (DBG) {
             log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
-                    (oldInfo == null ? "null" : oldInfo.getState()) +
-                    " to " + state);
+                    oldInfo.getState() + " to " + state);
         }
 
         if (!networkAgent.created
@@ -6593,8 +6591,8 @@
                 // TODO(b/122649188): send the broadcast only to VPN users.
                 mProxyTracker.sendProxyBroadcast();
             }
-        } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
-                state == NetworkInfo.State.SUSPENDED) {
+        } else if (networkAgent.created && (oldInfo.getState() == NetworkInfo.State.SUSPENDED ||
+                state == NetworkInfo.State.SUSPENDED)) {
             // going into or coming out of SUSPEND: re-score and notify
             if (networkAgent.getCurrentScore() != oldScore) {
                 rematchAllNetworksAndRequests(networkAgent, oldScore);
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index f92d0e0..173d5b0 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -21,6 +21,7 @@
 import android.gsi.GsiInstallParams;
 import android.gsi.GsiProgress;
 import android.gsi.IGsiService;
+import android.gsi.IGsid;
 import android.os.Environment;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
@@ -61,7 +62,9 @@
          * re-initialized in this case.
          */
         binder.linkToDeath(recipient, 0);
-        return IGsiService.Stub.asInterface(binder);
+
+        IGsid gsid = IGsid.Stub.asInterface(binder);
+        return gsid.getClient();
     }
 
     /** implements DeathRecipient */
@@ -159,7 +162,7 @@
             isInUse = getGsiService().isGsiRunning();
         } finally {
             if (!gsidWasRunning && !isInUse) {
-                SystemProperties.set("ctl.stop", "gsid");
+                mGsiService = null;
             }
         }
 
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 4d39f9a..bec08f4 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -39,6 +39,12 @@
 27391 user_activity_timeout_override (override|2|3)
 27392 battery_saver_setting (threshold|1)
 
+
+# ---------------------------
+# ThermalManagerService.java
+# ---------------------------
+2737 thermal_changed (name|3),(type|1|5),(temperature|5),(sensor_status|1|5),(previous_system_status|1|5)
+
 #
 # Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
 #
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 097a7d6..b0efd43 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -21,7 +21,6 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
-
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.IActivityManager;
@@ -59,24 +58,23 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
-
 import com.android.server.wm.ActivityTaskManagerInternal;
+
 import dalvik.system.DexFile;
 import dalvik.system.VMRuntime;
 
-import java.io.FileDescriptor;
 import java.io.Closeable;
-import java.io.InputStream;
 import java.io.DataInputStream;
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.List;
 import java.util.ArrayList;
-
-import java.util.zip.ZipFile;
+import java.util.List;
 import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
 /**
  * <p>PinnerService pins important files for key processes in memory.</p>
@@ -573,17 +571,9 @@
         }
 
         // determine the ABI from either ApplicationInfo or Build
-        String arch = "arm";
-        if (appInfo.primaryCpuAbi != null) {
-            if (VMRuntime.is64BitAbi(appInfo.primaryCpuAbi)) {
-                arch = arch + "64";
-            }
-        } else {
-            if (VMRuntime.is64BitAbi(Build.SUPPORTED_ABIS[0])) {
-                arch = arch + "64";
-            }
-        }
-
+        String abi = appInfo.primaryCpuAbi != null ? appInfo.primaryCpuAbi :
+                Build.SUPPORTED_ABIS[0];
+        String arch = VMRuntime.getInstructionSet(abi);
         // get the path to the odex or oat file
         String baseCodePath = appInfo.getBaseCodePath();
         String[] files = null;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index f7e825e..e66e596 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1027,12 +1027,7 @@
                 log(str);
             }
             mLocalLog.log(str);
-            // for service state updates, don't notify clients when subId is invalid. This prevents
-            // us from sending incorrect notifications like b/133140128
-            // In the future, we can remove this logic for every notification here and add a
-            // callback so listeners know when their PhoneStateListener's subId becomes invalid, but
-            // for now we use the simplest fix.
-            if (validatePhoneId(phoneId) && SubscriptionManager.isValidSubscriptionId(subId)) {
+            if (validatePhoneId(phoneId)) {
                 mServiceState[phoneId] = state;
 
                 for (Record r : mRecords) {
@@ -1064,8 +1059,7 @@
                     }
                 }
             } else {
-                log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId
-                        + " or subId=" + subId);
+                log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
             }
             handleRemoveListLocked();
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f3264e2..c66b3fa 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2373,11 +2373,6 @@
         }
     }
 
-    @VisibleForTesting
-    public ActivityManagerService(Injector injector) {
-        this(injector, null /* handlerThread */);
-    }
-
     /**
      * Provides the basic functionality for activity task related tests when a handler thread is
      * given to initialize the dependency members.
@@ -7901,11 +7896,14 @@
     }
 
     void reportGlobalUsageEventLocked(int event) {
-        mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME,
-                mUserController.getCurrentUserId(), event);
+        final int currentUserId = mUserController.getCurrentUserId();
+        mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME, currentUserId, event);
         int[] profiles = mUserController.getCurrentProfileIds();
         if (profiles != null) {
             for (int i = profiles.length - 1; i >= 0; i--) {
+                if (profiles[i] == currentUserId) {
+                    continue;
+                }
                 mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME, profiles[i], event);
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 0dd7199..a0900b6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -528,12 +528,12 @@
                 options.setLockTaskEnabled(true);
             }
             if (mWaitOption) {
-                result = mInternal.startActivityAndWait(null, null, intent, mimeType,
+                result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, intent, mimeType,
                         null, null, 0, mStartFlags, profilerInfo,
                         options != null ? options.toBundle() : null, mUserId);
                 res = result.result;
             } else {
-                res = mInternal.startActivityAsUser(null, null, intent, mimeType,
+                res = mInternal.startActivityAsUser(null, SHELL_PACKAGE_NAME, intent, mimeType,
                         null, null, 0, mStartFlags, profilerInfo,
                         options != null ? options.toBundle() : null, mUserId);
             }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index cb6cf74..6010b1dc 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -15,9 +15,6 @@
  */
 package com.android.server.audio;
 
-import static com.android.server.audio.AudioService.CONNECTION_STATE_CONNECTED;
-import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTED;
-
 import android.annotation.NonNull;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothDevice;
@@ -95,13 +92,28 @@
     /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
         mContext = context;
         mAudioService = service;
-        setupMessaging(context);
         mBtHelper = new BtHelper(this);
         mDeviceInventory = new AudioDeviceInventory(this);
 
+        init();
+    }
+
+    /** for test purposes only, inject AudioDeviceInventory */
+    AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service,
+                      @NonNull AudioDeviceInventory mockDeviceInventory) {
+        mContext = context;
+        mAudioService = service;
+        mBtHelper = new BtHelper(this);
+        mDeviceInventory = mockDeviceInventory;
+
+        init();
+    }
+
+    private void init() {
+        setupMessaging(mContext);
+
         mForcedUseForComm = AudioSystem.FORCE_NONE;
         mForcedUseForCommExt = mForcedUseForComm;
-
     }
 
     /*package*/ Context getContext() {
@@ -232,17 +244,42 @@
             mSupprNoisy = suppressNoisyIntent;
             mVolume = vol;
         }
+
+        // redefine equality op so we can match messages intended for this device
+        @Override
+        public boolean equals(Object o) {
+            return mDevice.equals(o);
+        }
     }
 
+
     /*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
             @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
             int profile, boolean suppressNoisyIntent, int a2dpVolume) {
         final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
                 suppressNoisyIntent, a2dpVolume);
 
-        // TODO add a check to try to remove unprocessed messages for the same device (the old
-        //      check didn't work), and  make sure it doesn't conflict with config change message
-        sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
+        // when receiving a request to change the connection state of a device, this last request
+        // is the source of truth, so cancel all previous requests
+        removeAllA2dpConnectionEvents(device);
+
+        sendLMsgNoDelay(
+                state == BluetoothProfile.STATE_CONNECTED
+                        ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION
+                        : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
+                SENDMSG_QUEUE, info);
+    }
+
+    /** remove all previously scheduled connection and disconnection events for the given device */
+    private void removeAllA2dpConnectionEvents(@NonNull BluetoothDevice device) {
+        mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
+                device);
+        mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION,
+                device);
+        mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
+                device);
+        mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
+                device);
     }
 
     private static final class HearingAidDeviceConnectionInfo {
@@ -430,13 +467,16 @@
         sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
     }
 
-    /*package*/ void postA2dpSinkConnection(int state,
+    /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state,
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
-        sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE,
+        sendILMsg(state == BluetoothA2dp.STATE_CONNECTED
+                        ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED
+                        : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
+                SENDMSG_QUEUE,
                 state, btDeviceInfo, delay);
     }
 
-    /*package*/ void postA2dpSourceConnection(int state,
+    /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state,
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
         sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
                 state, btDeviceInfo, delay);
@@ -522,25 +562,6 @@
         }
     }
 
-    @GuardedBy("mDeviceStateLock")
-    /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
-                @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
-        final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
-                ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED;
-        final int delay = mDeviceInventory.checkSendBecomingNoisyIntent(
-                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
-                    AudioSystem.DEVICE_NONE);
-        final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress();
-
-        if (AudioService.DEBUG_DEVICES) {
-            Log.d(TAG, "handleSetA2dpSinkConnectionState btDevice= " + btDeviceInfo
-                    + " state= " + state
-                    + " is dock: " + btDeviceInfo.getBtDevice().isBluetoothDock());
-        }
-        sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE,
-                state, btDeviceInfo, delay);
-    }
-
     /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
         final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
@@ -575,8 +596,10 @@
 
     // must be called synchronized on mConnectedDevices
     /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) {
-        return mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE,
-                new BtHelper.BluetoothA2dpDeviceInfo(btDevice));
+        return (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
+                        new BtHelper.BluetoothA2dpDeviceInfo(btDevice))
+                || mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
+                        new BtHelper.BluetoothA2dpDeviceInfo(btDevice)));
     }
 
     /*package*/ void setA2dpDockTimeout(String address, int a2dpCodec, int delayMs) {
@@ -711,7 +734,8 @@
                         mDeviceInventory.onReportNewRoutes();
                     }
                     break;
-                case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
+                case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
+                case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
                     synchronized (mDeviceStateLock) {
                         mDeviceInventory.onSetA2dpSinkConnectionState(
                                 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
@@ -836,7 +860,8 @@
                         }
                     }
                     break;
-                case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: {
+                case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
+                case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: {
                     final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
                     AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
                             "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent "
@@ -887,7 +912,7 @@
     private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3;
     private static final int MSG_IIL_SET_FORCE_USE = 4;
     private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5;
-    private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE = 6;
+    private static final int MSG_TOGGLE_HDMI = 6;
     private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7;
     private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8;
     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
@@ -898,7 +923,6 @@
     private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
     private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
     private static final int MSG_I_DISCONNECT_BT_SCO = 16;
-    private static final int MSG_TOGGLE_HDMI = 17;
     private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
     private static final int MSG_DISCONNECT_A2DP = 19;
     private static final int MSG_DISCONNECT_A2DP_SINK = 20;
@@ -908,25 +932,30 @@
     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
+    private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27;
+    private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28;
     // process external command to (dis)connect an A2DP device
-    private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 27;
+    private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29;
+    private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30;
     // process external command to (dis)connect a hearing aid device
-    private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28;
+    private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
     // a ScoClient died in BtHelper
-    private static final int MSG_L_SCOCLIENT_DIED = 29;
+    private static final int MSG_L_SCOCLIENT_DIED = 32;
 
 
     private static boolean isMessageHandledUnderWakelock(int msgId) {
         switch(msgId) {
             case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
-            case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
+            case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
+            case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
             case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
             case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
             case MSG_IL_BTA2DP_DOCK_TIMEOUT:
             case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
             case MSG_TOGGLE_HDMI:
             case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
-            case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
+            case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
+            case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
             case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
                 return true;
             default:
@@ -1007,7 +1036,8 @@
 
             switch (msg) {
                 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
-                case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
+                case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
+                case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
                 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
                 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
                 case MSG_IL_BTA2DP_DOCK_TIMEOUT:
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index a9a8ef2..90973a8 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -41,14 +41,16 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
 
 /**
  * Class to manage the inventory of all connected devices.
  * This class is thread-safe.
+ * (non final for mocking/spying)
  */
-public final class AudioDeviceInventory {
+public class AudioDeviceInventory {
 
     private static final String TAG = "AS.AudioDeviceInventory";
 
@@ -56,11 +58,7 @@
     // Key for map created from DeviceInfo.makeDeviceListKey()
     private final ArrayMap<String, DeviceInfo> mConnectedDevices = new ArrayMap<>();
 
-    private final @NonNull AudioDeviceBroker mDeviceBroker;
-
-    AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
-        mDeviceBroker = broker;
-    }
+    private @NonNull AudioDeviceBroker mDeviceBroker;
 
     // cache of the address of the last dock the device was connected to
     private String mDockAddress;
@@ -70,6 +68,20 @@
     final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers =
             new RemoteCallbackList<IAudioRoutesObserver>();
 
+    /*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
+        mDeviceBroker = broker;
+    }
+
+    //-----------------------------------------------------------
+    /** for mocking only */
+    /*package*/ AudioDeviceInventory() {
+        mDeviceBroker = null;
+    }
+
+    /*package*/ void setDeviceBroker(@NonNull AudioDeviceBroker broker) {
+        mDeviceBroker = broker;
+    }
+
     //------------------------------------------------------------
     /**
      * Class to store info about connected devices.
@@ -146,8 +158,10 @@
         }
     }
 
+    // only public for mocking/spying
     @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
-    /*package*/ void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo,
+    @VisibleForTesting
+    public void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo,
             @AudioService.BtProfileConnectionState int state) {
         final BluetoothDevice btDevice = btInfo.getBtDevice();
         int a2dpVolume = btInfo.getVolume();
@@ -159,30 +173,40 @@
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
         }
-        AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
-                "A2DP sink connected: device addr=" + address + " state=" + state
-                        + " vol=" + a2dpVolume));
 
         final int a2dpCodec = btInfo.getCodec();
 
+        AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+                "A2DP sink connected: device addr=" + address + " state=" + state
+                        + " codec=" + a2dpCodec
+                        + " vol=" + a2dpVolume));
+
         synchronized (mConnectedDevices) {
             final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                     btDevice.getAddress());
             final DeviceInfo di = mConnectedDevices.get(key);
             boolean isConnected = di != null;
 
-            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
-                if (btDevice.isBluetoothDock()) {
-                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                        // introduction of a delay for transient disconnections of docks when
-                        // power is rapidly turned off/on, this message will be canceled if
-                        // we reconnect the dock under a preset delay
-                        makeA2dpDeviceUnavailableLater(address,
-                                AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS);
-                        // the next time isConnected is evaluated, it will be false for the dock
+            if (isConnected) {
+                if (state == BluetoothProfile.STATE_CONNECTED) {
+                    // device is already connected, but we are receiving a connection again,
+                    // it could be for a codec change
+                    if (a2dpCodec != di.mDeviceCodecFormat) {
+                        mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice);
                     }
                 } else {
-                    makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
+                    if (btDevice.isBluetoothDock()) {
+                        if (state == BluetoothProfile.STATE_DISCONNECTED) {
+                            // introduction of a delay for transient disconnections of docks when
+                            // power is rapidly turned off/on, this message will be canceled if
+                            // we reconnect the dock under a preset delay
+                            makeA2dpDeviceUnavailableLater(address,
+                                    AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS);
+                            // the next time isConnected is evaluated, it will be false for the dock
+                        }
+                    } else {
+                        makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
+                    }
                 }
             } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
                 if (btDevice.isBluetoothDock()) {
@@ -282,11 +306,9 @@
                     + " event=" + BtHelper.a2dpDeviceEventToString(event)));
 
         synchronized (mConnectedDevices) {
-            //TODO original CL is not consistent between BluetoothDevice and BluetoothA2dpDeviceInfo
-            // for this type of message
             if (mDeviceBroker.hasScheduledA2dpSinkConnectionState(btDevice)) {
                 AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
-                        "A2dp config change ignored"));
+                        "A2dp config change ignored (scheduled connection change)"));
                 return;
             }
             final String key = DeviceInfo.makeDeviceListKey(
@@ -534,8 +556,10 @@
         return mCurAudioRoutes;
     }
 
+    // only public for mocking/spying
     @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
-    /*package*/ void setBluetoothA2dpDeviceConnectionState(
+    @VisibleForTesting
+    public void setBluetoothA2dpDeviceConnectionState(
             @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
             int profile, boolean suppressNoisyIntent, int musicDevice, int a2dpVolume) {
         int delay;
@@ -544,9 +568,12 @@
         }
         synchronized (mConnectedDevices) {
             if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) {
-                int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
+                @AudioService.ConnectionState int asState =
+                        (state == BluetoothA2dp.STATE_CONNECTED)
+                                ? AudioService.CONNECTION_STATE_CONNECTED
+                                : AudioService.CONNECTION_STATE_DISCONNECTED;
                 delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                        intState, musicDevice);
+                        asState, musicDevice);
             } else {
                 delay = 0;
             }
@@ -785,7 +812,7 @@
                 return 0;
             }
             mDeviceBroker.postBroadcastBecomingNoisy();
-            delay = 1000;
+            delay = AudioService.BECOMING_NOISY_DELAY_MS;
         }
 
         return delay;
@@ -943,4 +970,21 @@
             intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
         }
     }
+
+    //----------------------------------------------------------
+    // For tests only
+
+    /**
+     * Check if device is in the list of connected devices
+     * @param device
+     * @return true if connected
+     */
+    @VisibleForTesting
+    public boolean isA2dpDeviceConnected(@NonNull BluetoothDevice device) {
+        final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                device.getAddress());
+        synchronized (mConnectedDevices) {
+            return (mConnectedDevices.get(key) != null);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7458bee..5bc2261 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -128,6 +128,7 @@
 import android.widget.Toast;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
@@ -190,6 +191,13 @@
     private static final int UNMUTE_STREAM_DELAY = 350;
 
     /**
+     * Delay before disconnecting a device that would cause BECOMING_NOISY intent to be sent,
+     * to give a chance to applications to pause.
+     */
+    @VisibleForTesting
+    public static final int BECOMING_NOISY_DELAY_MS = 1000;
+
+    /**
      * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
      */
     private static final int FLAG_ADJUST_VOLUME = 1;
@@ -3950,7 +3958,9 @@
                 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
     }
 
-    /*package*/ boolean isInCommunication() {
+    /** only public for mocking/spying, do not call outside of AudioService */
+    @VisibleForTesting
+    public boolean isInCommunication() {
         boolean IsInCall = false;
 
         TelecomManager telecomManager =
@@ -4119,7 +4129,9 @@
         return false;
     }
 
-    /*package*/ int getDeviceForStream(int stream) {
+    /** only public for mocking/spying, do not call outside of AudioService */
+    @VisibleForTesting
+    public int getDeviceForStream(int stream) {
         int device = getDevicesForStream(stream);
         if ((device & (device - 1)) != 0) {
             // Multiple device selection is either:
@@ -4164,7 +4176,9 @@
         }
     }
 
-    /*package*/ void postObserveDevicesForAllStreams() {
+    /** only public for mocking/spying, do not call outside of AudioService */
+    @VisibleForTesting
+    public void postObserveDevicesForAllStreams() {
         sendMsg(mAudioHandler,
                 MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS,
                 SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, null /*obj*/,
@@ -4275,7 +4289,9 @@
             AudioSystem.DEVICE_OUT_ALL_USB |
             AudioSystem.DEVICE_OUT_HDMI;
 
-    /*package*/ void postAccessoryPlugMediaUnmute(int newDevice) {
+    /** only public for mocking/spying, do not call outside of AudioService */
+    @VisibleForTesting
+    public void postAccessoryPlugMediaUnmute(int newDevice) {
         sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
                 newDevice, 0, null, 0);
     }
@@ -4825,7 +4841,9 @@
         }
     }
 
-    /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
+    /** only public for mocking/spying, do not call outside of AudioService */
+    @VisibleForTesting
+    public void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
                                                 String caller) {
         sendMsg(mAudioHandler,
                 MSG_SET_DEVICE_STREAM_VOLUME,
@@ -5183,7 +5201,9 @@
      * @return true if there is currently a registered dynamic mixing policy that affects media
      * and is not a render + loopback policy
      */
-    /*package*/ boolean hasMediaDynamicPolicy() {
+    // only public for mocking/spying
+    @VisibleForTesting
+    public boolean hasMediaDynamicPolicy() {
         synchronized (mAudioPolicies) {
             if (mAudioPolicies.isEmpty()) {
                 return false;
@@ -5516,7 +5536,9 @@
         return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
     }
 
-    /*package*/ boolean hasAudioFocusUsers() {
+    /** only public for mocking/spying, do not call outside of AudioService */
+    @VisibleForTesting
+    public boolean hasAudioFocusUsers() {
         return mMediaFocusControl.hasAudioFocusUsers();
     }
 
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 1a63f8f..9f1a6bd 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -139,6 +139,12 @@
         public int getCodec() {
             return mCodec;
         }
+
+        // redefine equality op so we can match messages intended for this device
+        @Override
+        public boolean equals(Object o) {
+            return mBtDevice.equals(o);
+        }
     }
 
     // A2DP device events
@@ -441,9 +447,9 @@
             return;
         }
         final BluetoothDevice btDevice = deviceList.get(0);
-        final @BluetoothProfile.BtProfileState int state = mA2dp.getConnectionState(btDevice);
-        mDeviceBroker.handleSetA2dpSinkConnectionState(
-                state, new BluetoothA2dpDeviceInfo(btDevice));
+        // the device is guaranteed CONNECTED
+        mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(btDevice,
+                BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK, true, -1);
     }
 
     /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 5b04379..8d1a802 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.IDnsResolver;
 import android.net.INetd;
@@ -116,7 +117,7 @@
 // not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
 public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
 
-    public NetworkInfo networkInfo;
+    @NonNull public NetworkInfo networkInfo;
     // This Network object should always be used if possible, so as to encourage reuse of the
     // enclosed socket factory and connection pool.  Avoid creating other Network objects.
     // This Network object is always valid.
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 4957eed..73d160d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -772,7 +772,6 @@
                     case WifiManager.WIFI_AP_STATE_FAILED:
                     default:
                         disableWifiIpServingLocked(ifname, curState);
-                        mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
                         break;
                 }
             }
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 78a48da..c45a314 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -728,6 +728,7 @@
 
         private SensorManager mSensorManager;
         private Sensor mLightSensor;
+        private LightSensorEventListener mLightSensorListener = new LightSensorEventListener();
         // Take it as low brightness before valid sensor data comes
         private float mAmbientLux = -1.0f;
         private AmbientFilter mAmbientFilter;
@@ -907,19 +908,40 @@
                 mSensorManager.registerListener(mLightSensorListener,
                         mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
             } else {
+                mLightSensorListener.removeCallbacks();
                 mSensorManager.unregisterListener(mLightSensorListener);
             }
         }
 
-        private final SensorEventListener mLightSensorListener = new SensorEventListener() {
+        private final class LightSensorEventListener implements SensorEventListener {
+            final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
+            private float mLastSensorData;
+
             @Override
             public void onSensorChanged(SensorEvent event) {
-                long now = SystemClock.uptimeMillis();
-                mAmbientFilter.addValue(now, event.values[0]);
-                mAmbientLux = mAmbientFilter.getEstimate(now);
+                mLastSensorData = event.values[0];
+                if (DEBUG) {
+                    Slog.d(TAG, "On sensor changed: " + mLastSensorData);
+                }
 
-                synchronized (mLock) {
-                    onBrightnessChangedLocked();
+                boolean zoneChanged = isDifferentZone(mLastSensorData, mAmbientLux);
+                if (zoneChanged && mLastSensorData < mAmbientLux) {
+                    // Easier to see flicker at lower brightness environment. Forget the history to
+                    // get immediate response.
+                    mAmbientFilter.clear();
+                }
+
+                long now = SystemClock.uptimeMillis();
+                mAmbientFilter.addValue(now, mLastSensorData);
+
+                mHandler.removeCallbacks(mInjectSensorEventRunnable);
+                processSensorData(now);
+
+                if (zoneChanged && mLastSensorData > mAmbientLux) {
+                    // Sensor may not report new event if there is no brightness change.
+                    // Need to keep querying the temporal filter for the latest estimation,
+                    // until enter in higher lux zone or is interrupted by a new sensor event.
+                    mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
                 }
             }
 
@@ -927,6 +949,47 @@
             public void onAccuracyChanged(Sensor sensor, int accuracy) {
                 // Not used.
             }
+
+            public void removeCallbacks() {
+                mHandler.removeCallbacks(mInjectSensorEventRunnable);
+            }
+
+            private void processSensorData(long now) {
+                mAmbientLux = mAmbientFilter.getEstimate(now);
+
+                synchronized (mLock) {
+                    onBrightnessChangedLocked();
+                }
+            }
+
+            private boolean isDifferentZone(float lux1, float lux2) {
+                for (int z = 0; z < mAmbientBrightnessThresholds.length; z++) {
+                    final float boundary = mAmbientBrightnessThresholds[z];
+
+                    // Test each boundary. See if the current value and the new value are at
+                    // different sides.
+                    if ((lux1 <= boundary && lux2 > boundary)
+                            || (lux1 > boundary && lux2 <= boundary)) {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            private Runnable mInjectSensorEventRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    long now = SystemClock.uptimeMillis();
+                    // No need to really inject the last event into a temporal filter.
+                    processSensorData(now);
+
+                    // Inject next event if there is a possible zone change.
+                    if (isDifferentZone(mLastSensorData, mAmbientLux)) {
+                        mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
+                    }
+                }
+            };
         };
 
         private final class ScreenStateReceiver extends BroadcastReceiver {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index 2c0cacd..52cede2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -290,8 +290,7 @@
             new KeycodeEntry(KeyEvent.KEYCODE_CHANNEL_UP, CEC_KEYCODE_CHANNEL_UP),
             new KeycodeEntry(KeyEvent.KEYCODE_CHANNEL_DOWN, CEC_KEYCODE_CHANNEL_DOWN),
             new KeycodeEntry(KeyEvent.KEYCODE_LAST_CHANNEL, CEC_KEYCODE_PREVIOUS_CHANNEL),
-            // No Android keycode defined for CEC_KEYCODE_SOUND_SELECT
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SOUND_SELECT),
+            new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK, CEC_KEYCODE_SOUND_SELECT),
             new KeycodeEntry(KeyEvent.KEYCODE_TV_INPUT, CEC_KEYCODE_INPUT_SELECT),
             new KeycodeEntry(KeyEvent.KEYCODE_INFO, CEC_KEYCODE_DISPLAY_INFORMATION),
             // No Android keycode defined for CEC_KEYCODE_HELP
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 09e9375..f20003a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2551,7 +2551,7 @@
             final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
             if (mStatusBar != null) {
                 mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
-                        needsToShowImeSwitcher);
+                        needsToShowImeSwitcher, false /*isMultiClientImeEnabled*/);
             }
             final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
             if (imi != null && needsToShowImeSwitcher) {
diff --git a/core/java/android/view/inputmethod/InputMethodSystemProperty.java b/services/core/java/com/android/server/inputmethod/InputMethodSystemProperty.java
similarity index 81%
rename from core/java/android/view/inputmethod/InputMethodSystemProperty.java
rename to services/core/java/com/android/server/inputmethod/InputMethodSystemProperty.java
index e20c2fd..a6a6893 100644
--- a/core/java/android/view/inputmethod/InputMethodSystemProperty.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSystemProperty.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.view.inputmethod;
+package com.android.server.inputmethod;
 
 import android.annotation.Nullable;
 import android.content.ComponentName;
@@ -23,8 +23,6 @@
 
 /**
  * Various (pseudo) constants about IME behaviors.
- *
- * @hide
  */
 public class InputMethodSystemProperty {
     /**
@@ -58,23 +56,12 @@
 
     /**
      * {@link ComponentName} of multi-client IME to be used.
-     *
-     * <p>TODO: Move this back to MultiClientInputMethodManagerService once
-     * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p>
-     *
-     * @hide
      */
     @Nullable
-    public static final ComponentName sMultiClientImeComponentName =
-            getMultiClientImeComponentName();
+    static final ComponentName sMultiClientImeComponentName = getMultiClientImeComponentName();
 
     /**
      * {@code true} when multi-client IME is enabled.
-     *
-     * <p>TODO: Move this back to MultiClientInputMethodManagerService once
-     * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p>
-     *
-     * @hide
      */
     public static final boolean MULTI_CLIENT_IME_ENABLED = (sMultiClientImeComponentName != null);
 }
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 3dd7304..02e29e0 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -67,7 +67,6 @@
 import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
-import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9510db0..f1f6d50 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -182,7 +182,7 @@
     @IntDef({CHALLENGE_NONE,
             CHALLENGE_FROM_CALLER,
             CHALLENGE_INTERNAL})
-    @interface ChallengeType {};
+    @interface ChallengeType {}
 
     // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
     // Do not call into ActivityManager while holding mSpManager lock.
@@ -1853,26 +1853,11 @@
             return VerifyCredentialResponse.ERROR;
         }
 
-        boolean shouldReEnrollBaseZero = storedHash.type == CREDENTIAL_TYPE_PATTERN
-                && storedHash.isBaseZeroPattern;
-
-        byte[] credentialToVerify;
-        if (shouldReEnrollBaseZero) {
-            credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential);
-        } else {
-            credentialToVerify = credential;
-        }
-
-        response = verifyCredential(userId, storedHash, credentialToVerify,
+        response = verifyCredential(userId, storedHash, credential,
                 challengeType, challenge, progressCallback);
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
             mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
-            if (shouldReEnrollBaseZero) {
-                setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
-                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId, false,
-                        /* isLockTiedToParent= */ false);
-            }
         }
 
         return response;
@@ -1937,46 +1922,6 @@
         // of unlocking the user, so yell if calling from the main thread.
         StrictMode.noteDiskRead();
 
-        if (storedHash.version == CredentialHash.VERSION_LEGACY) {
-            final byte[] hash;
-            if (storedHash.type == CREDENTIAL_TYPE_PATTERN) {
-                hash = LockPatternUtils.patternToHash(
-                        LockPatternUtils.byteArrayToPattern(credential));
-            } else {
-                hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes();
-            }
-            if (Arrays.equals(hash, storedHash.hash)) {
-                if (storedHash.type == CREDENTIAL_TYPE_PATTERN) {
-                    unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId);
-                } else {
-                    unlockKeystore(credential, userId);
-                }
-                // Users with legacy credentials don't have credential-backed
-                // FBE keys, so just pass through a fake token/secret
-                Slog.i(TAG, "Unlocking user with fake token: " + userId);
-                final byte[] fakeToken = String.valueOf(userId).getBytes();
-                unlockUser(userId, fakeToken, fakeToken);
-
-                // migrate credential to GateKeeper
-                setLockCredentialInternal(credential, storedHash.type, null,
-                        storedHash.type == CREDENTIAL_TYPE_PATTERN
-                                ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
-                                : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
-                                /* TODO(roosa): keep the same password quality */,
-                        userId, false, /* isLockTiedToParent= */ false);
-                if (challengeType == CHALLENGE_NONE) {
-                    notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
-                    // Use credentials to create recoverable keystore snapshot.
-                    sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId);
-                    return VerifyCredentialResponse.OK;
-                }
-                // Fall through to get the auth token. Technically this should never happen,
-                // as a user that had a legacy credential would have to unlock their device
-                // before getting to a flow with a challenge, but supporting for consistency.
-            } else {
-                return VerifyCredentialResponse.ERROR;
-            }
-        }
         GateKeeperResponse gateKeeperResponse = getGateKeeperService()
                 .verifyChallenge(userId, challenge, storedHash.hash, credential);
         VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 84ae7c7..29b8aa2 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -77,10 +77,7 @@
 
     private static final String SYSTEM_DIRECTORY = "/system/";
     private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key";
-    private static final String BASE_ZERO_LOCK_PATTERN_FILE = "gatekeeper.gesture.key";
-    private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key";
     private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key";
-    private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key";
     private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key";
 
     private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";
@@ -96,59 +93,43 @@
 
     @VisibleForTesting
     public static class CredentialHash {
-        static final int VERSION_LEGACY = 0;
-        static final int VERSION_GATEKEEPER = 1;
+        /** Deprecated private static final int VERSION_LEGACY = 0; */
+        private static final int VERSION_GATEKEEPER = 1;
 
-        private CredentialHash(byte[] hash, @CredentialType int type, int version) {
-            this(hash, type, version, false /* isBaseZeroPattern */);
-        }
-
-        private CredentialHash(
-                byte[] hash, @CredentialType int type, int version, boolean isBaseZeroPattern) {
+        private CredentialHash(byte[] hash, @CredentialType int type) {
             if (type != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
                 if (hash == null) {
-                    throw new RuntimeException("Empty hash for CredentialHash");
+                    throw new IllegalArgumentException("Empty hash for CredentialHash");
                 }
             } else /* type == LockPatternUtils.CREDENTIAL_TYPE_NONE */ {
                 if (hash != null) {
-                    throw new RuntimeException("None type CredentialHash should not have hash");
+                    throw new IllegalArgumentException(
+                            "None type CredentialHash should not have hash");
                 }
             }
             this.hash = hash;
             this.type = type;
-            this.version = version;
-            this.isBaseZeroPattern = isBaseZeroPattern;
-        }
-
-        private static CredentialHash createBaseZeroPattern(byte[] hash) {
-            return new CredentialHash(hash, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    VERSION_GATEKEEPER, true /* isBaseZeroPattern */);
         }
 
         static CredentialHash create(byte[] hash, int type) {
             if (type == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
-                throw new RuntimeException("Bad type for CredentialHash");
+                throw new IllegalArgumentException("Bad type for CredentialHash");
             }
-            return new CredentialHash(hash, type, VERSION_GATEKEEPER);
+            return new CredentialHash(hash, type);
         }
 
         static CredentialHash createEmptyHash() {
-            return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
-                    VERSION_GATEKEEPER);
+            return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE);
         }
 
         byte[] hash;
         @CredentialType int type;
-        int version;
-        boolean isBaseZeroPattern;
 
         public byte[] toBytes() {
-            Preconditions.checkState(!isBaseZeroPattern, "base zero patterns are not serializable");
-
             try {
                 ByteArrayOutputStream os = new ByteArrayOutputStream();
                 DataOutputStream dos = new DataOutputStream(os);
-                dos.write(version);
+                dos.write(VERSION_GATEKEEPER);
                 dos.write(type);
                 if (hash != null && hash.length > 0) {
                     dos.writeInt(hash.length);
@@ -166,7 +147,7 @@
         public static CredentialHash fromBytes(byte[] bytes) {
             try {
                 DataInputStream is = new DataInputStream(new ByteArrayInputStream(bytes));
-                int version = is.read();
+                /* int version = */ is.read();
                 int type = is.read();
                 int hashSize = is.readInt();
                 byte[] hash = null;
@@ -174,7 +155,7 @@
                     hash = new byte[hashSize];
                     is.readFully(hash);
                 }
-                return new CredentialHash(hash, type, version);
+                return new CredentialHash(hash, type);
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
@@ -269,14 +250,7 @@
     private CredentialHash readPasswordHashIfExists(int userId) {
         byte[] stored = readFile(getLockPasswordFilename(userId));
         if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                    CredentialHash.VERSION_GATEKEEPER);
-        }
-
-        stored = readFile(getLegacyLockPasswordFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                    CredentialHash.VERSION_LEGACY);
+            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
         }
         return null;
     }
@@ -284,39 +258,22 @@
     private CredentialHash readPatternHashIfExists(int userId) {
         byte[] stored = readFile(getLockPatternFilename(userId));
         if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    CredentialHash.VERSION_GATEKEEPER);
-        }
-
-        stored = readFile(getBaseZeroLockPatternFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return CredentialHash.createBaseZeroPattern(stored);
-        }
-
-        stored = readFile(getLegacyLockPatternFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    CredentialHash.VERSION_LEGACY);
+            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
         }
         return null;
     }
 
     public CredentialHash readCredentialHash(int userId) {
         CredentialHash passwordHash = readPasswordHashIfExists(userId);
-        CredentialHash patternHash = readPatternHashIfExists(userId);
-        if (passwordHash != null && patternHash != null) {
-            if (passwordHash.version == CredentialHash.VERSION_GATEKEEPER) {
-                return passwordHash;
-            } else {
-                return patternHash;
-            }
-        } else if (passwordHash != null) {
+        if (passwordHash != null) {
             return passwordHash;
-        } else if (patternHash != null) {
-            return patternHash;
-        } else {
-            return CredentialHash.createEmptyHash();
         }
+
+        CredentialHash patternHash = readPatternHashIfExists(userId);
+        if (patternHash != null) {
+            return patternHash;
+        }
+        return CredentialHash.createEmptyHash();
     }
 
     public void removeChildProfileLock(int userId) {
@@ -342,14 +299,11 @@
     }
 
     public boolean hasPassword(int userId) {
-        return hasFile(getLockPasswordFilename(userId)) ||
-            hasFile(getLegacyLockPasswordFilename(userId));
+        return hasFile(getLockPasswordFilename(userId));
     }
 
     public boolean hasPattern(int userId) {
-        return hasFile(getLockPatternFilename(userId)) ||
-            hasFile(getBaseZeroLockPatternFilename(userId)) ||
-            hasFile(getLegacyLockPatternFilename(userId));
+        return hasFile(getLockPatternFilename(userId));
     }
 
     public boolean hasCredential(int userId) {
@@ -470,20 +424,6 @@
     }
 
     @VisibleForTesting
-    String getLegacyLockPatternFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PATTERN_FILE);
-    }
-
-    @VisibleForTesting
-    String getLegacyLockPasswordFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PASSWORD_FILE);
-    }
-
-    private String getBaseZeroLockPatternFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, BASE_ZERO_LOCK_PATTERN_FILE);
-    }
-
-    @VisibleForTesting
     String getChildProfileLockFile(int userId) {
         return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE);
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 20dbe01..6fe924e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1854,6 +1854,7 @@
                     }
                     if (properties.getKeyset()
                             .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
+                        mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
                         mAssistants.resetDefaultAssistantsIfNecessary();
                     }
                 });
@@ -5228,7 +5229,7 @@
         @Override
         public void run() {
             synchronized (mNotificationLock) {
-                final NotificationRecord r = findNotificationByKeyLocked(mKey);
+                final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(mKey);
                 if (r != null) {
                     snoozeLocked(r);
                 }
@@ -5238,33 +5239,34 @@
         @GuardedBy("mNotificationLock")
         void snoozeLocked(NotificationRecord r) {
             if (r.sbn.isGroup()) {
-                final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
+                final List<NotificationRecord> groupNotifications =
+                        findCurrentAndSnoozedGroupNotificationsLocked(
                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
                 if (r.getNotification().isGroupSummary()) {
-                    // snooze summary and all children
+                    // snooze all children
                     for (int i = 0; i < groupNotifications.size(); i++) {
-                        snoozeNotificationLocked(groupNotifications.get(i));
+                        if (mKey != groupNotifications.get(i).getKey()) {
+                            snoozeNotificationLocked(groupNotifications.get(i));
+                        }
                     }
                 } else {
                     // if there is a valid summary for this group, and we are snoozing the only
                     // child, also snooze the summary
                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
-                        if (groupNotifications.size() != 2) {
-                            snoozeNotificationLocked(r);
-                        } else {
+                        if (groupNotifications.size() == 2) {
                             // snooze summary and the one child
                             for (int i = 0; i < groupNotifications.size(); i++) {
-                                snoozeNotificationLocked(groupNotifications.get(i));
+                                if (mKey != groupNotifications.get(i).getKey()) {
+                                    snoozeNotificationLocked(groupNotifications.get(i));
+                                }
                             }
                         }
-                    } else {
-                        snoozeNotificationLocked(r);
                     }
                 }
-            } else {
-                // just snooze the one notification
-                snoozeNotificationLocked(r);
             }
+            // snooze the notification
+            snoozeNotificationLocked(r);
+
         }
 
         @GuardedBy("mNotificationLock")
@@ -7049,6 +7051,15 @@
     }
 
     @GuardedBy("mNotificationLock")
+    @NonNull
+    List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg,
+            String groupKey, int userId) {
+        List<NotificationRecord> records = mSnoozeHelper.getNotifications(pkg, groupKey, userId);
+        records.addAll(findGroupNotificationsLocked(pkg, groupKey, userId));
+        return records;
+    }
+
+    @GuardedBy("mNotificationLock")
     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
             String groupKey, int userId) {
         List<NotificationRecord> records = new ArrayList<>();
@@ -7058,6 +7069,15 @@
         return records;
     }
 
+    @GuardedBy("mNotificationLock")
+    private NotificationRecord findInCurrentAndSnoozedNotificationByKeyLocked(String key) {
+        NotificationRecord r = findNotificationByKeyLocked(key);
+        if (r == null) {
+            r = mSnoozeHelper.getNotification(key);
+        }
+        return r;
+
+    }
 
     @GuardedBy("mNotificationLock")
     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index abc9841..91f497c 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -17,7 +17,6 @@
 
 import android.annotation.NonNull;
 import android.app.AlarmManager;
-import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -104,6 +103,46 @@
         return Collections.EMPTY_LIST;
     }
 
+    @NonNull
+    ArrayList<NotificationRecord> getNotifications(String pkg,
+            String groupKey, Integer userId) {
+        ArrayList<NotificationRecord> records =  new ArrayList<>();
+        if (mSnoozedNotifications.containsKey(userId)
+                && mSnoozedNotifications.get(userId).containsKey(pkg)) {
+            ArrayMap<String, NotificationRecord> packages =
+                    mSnoozedNotifications.get(userId).get(pkg);
+            for (int i = 0; i < packages.size(); i++) {
+                String currentGroupKey = packages.valueAt(i).sbn.getGroup();
+                if (currentGroupKey.equals(groupKey)) {
+                    records.add(packages.valueAt(i));
+                }
+            }
+        }
+        return records;
+    }
+
+    protected NotificationRecord getNotification(String key) {
+        List<NotificationRecord> snoozedForUser = new ArrayList<>();
+        IntArray userIds = mUserProfiles.getCurrentProfileIds();
+        if (userIds != null) {
+            final int userIdsSize = userIds.size();
+            for (int i = 0; i < userIdsSize; i++) {
+                final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
+                        mSnoozedNotifications.get(userIds.get(i));
+                if (snoozedPkgs != null) {
+                    final int snoozedPkgsSize = snoozedPkgs.size();
+                    for (int j = 0; j < snoozedPkgsSize; j++) {
+                        final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
+                        if (records != null) {
+                            return records.get(key);
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
     protected @NonNull List<NotificationRecord> getSnoozed() {
         List<NotificationRecord> snoozedForUser = new ArrayList<>();
         IntArray userIds = mUserProfiles.getCurrentProfileIds();
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
new file mode 100644
index 0000000..c87ab97
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.permission.IPermissionManager;
+import android.provider.DeviceConfig;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+
+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.Set;
+
+/**
+ * The entity responsible for filtering visibility between apps based on declarations in their
+ * manifests.
+ */
+class AppsFilter {
+
+    private static final String TAG = PackageManagerService.TAG;
+    /**
+     * This contains a list of packages that are implicitly queryable because another app explicitly
+     * interacted with it. For example, if application A starts a service in application B,
+     * application B is implicitly allowed to query for application A; regardless of any manifest
+     * entries.
+     */
+    private final SparseArray<HashMap<String, ArrayList<String>>> mImplicitlyQueryable =
+            new SparseArray<>();
+
+    /**
+     * A mapping from the set of packages that query other packages via package name to the
+     * list of packages that they can see.
+     */
+    private final HashMap<String, List<String>> mQueriesViaPackage = new HashMap<>();
+
+    /**
+     * A mapping from the set of packages that query others via intent to the list
+     * of packages that the intents resolve to.
+     */
+    private final HashMap<String, List<String>> mQueriesViaIntent = new HashMap<>();
+
+    /**
+     * A set of packages that are always queryable by any package, regardless of their manifest
+     * content.
+     */
+    private final HashSet<String> mForceQueryable;
+    /**
+     * A set of packages that are always queryable by any package, regardless of their manifest
+     * content.
+     */
+    private final Set<String> mForceQueryableByDevice;
+
+    /** True if all system apps should be made queryable by default. */
+    private final boolean mSystemAppsQueryable;
+
+    private final IPermissionManager mPermissionManager;
+
+    private final AppOpsManager mAppOpsManager;
+    private final ConfigProvider mConfigProvider;
+
+    AppsFilter(ConfigProvider configProvider, IPermissionManager permissionManager,
+            AppOpsManager appOpsManager, String[] forceQueryableWhitelist,
+            boolean systemAppsQueryable) {
+        mConfigProvider = configProvider;
+        mAppOpsManager = appOpsManager;
+        final HashSet<String> forceQueryableByDeviceSet = new HashSet<>();
+        Collections.addAll(forceQueryableByDeviceSet, forceQueryableWhitelist);
+        this.mForceQueryableByDevice = Collections.unmodifiableSet(forceQueryableByDeviceSet);
+        this.mForceQueryable = new HashSet<>();
+        mPermissionManager = permissionManager;
+        mSystemAppsQueryable = systemAppsQueryable;
+    }
+
+    public static AppsFilter create(Context context) {
+        final boolean forceSystemAppsQueryable =
+                context.getResources().getBoolean(R.bool.config_forceSystemPackagesQueryable);
+        final ConfigProvider configProvider = () -> DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                "package_query_filtering_enabled",
+                false);
+        final String[] forcedQueryablePackageNames;
+        if (forceSystemAppsQueryable) {
+            // all system apps already queryable, no need to read and parse individual exceptions
+            forcedQueryablePackageNames = new String[]{};
+        } else {
+            forcedQueryablePackageNames =
+                    context.getResources().getStringArray(R.array.config_forceQueryablePackages);
+            for (int i = 0; i < forcedQueryablePackageNames.length; i++) {
+                forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern();
+            }
+        }
+        IPermissionManager permissionmgr =
+                (IPermissionManager) ServiceManager.getService("permissionmgr");
+        return new AppsFilter(configProvider, permissionmgr,
+                context.getSystemService(AppOpsManager.class), forcedQueryablePackageNames,
+                forceSystemAppsQueryable);
+    }
+
+    /** Returns true if the querying package may query for the potential target package */
+    private static boolean canQuery(PackageParser.Package querying,
+            PackageParser.Package potentialTarget) {
+        if (querying.mQueriesIntents == null) {
+            return false;
+        }
+        for (Intent intent : querying.mQueriesIntents) {
+            for (PackageParser.Activity activity : potentialTarget.activities) {
+                if (activity.intents != null) {
+                    for (PackageParser.ActivityIntentInfo filter : activity.intents) {
+                        if (matches(intent, filter)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /** Returns true if the given intent matches the given filter. */
+    private static boolean matches(Intent intent, PackageParser.ActivityIntentInfo filter) {
+        return filter.match(intent.getAction(), intent.getType(), intent.getScheme(),
+                intent.getData(), intent.getCategories(), "AppsFilter") > 0;
+    }
+
+    /**
+     * Marks that a package initiated an interaction with another package, granting visibility of
+     * the prior from the former.
+     *
+     * @param initiatingPackage the package initiating the interaction
+     * @param targetPackage     the package being interacted with and thus gaining visibility of the
+     *                          initiating package.
+     * @param userId            the user in which this interaction was taking place
+     */
+    private void markAppInteraction(
+            PackageSetting initiatingPackage, PackageSetting targetPackage, int userId) {
+        HashMap<String, ArrayList<String>> currentUser = mImplicitlyQueryable.get(userId);
+        if (currentUser == null) {
+            currentUser = new HashMap<>();
+            mImplicitlyQueryable.put(userId, currentUser);
+        }
+        if (!currentUser.containsKey(targetPackage.pkg.packageName)) {
+            currentUser.put(targetPackage.pkg.packageName, new ArrayList<>());
+        }
+        currentUser.get(targetPackage.pkg.packageName).add(initiatingPackage.pkg.packageName);
+    }
+
+    /**
+     * Adds a package that should be considered when filtering visibility between apps.
+     *
+     * @param newPkg   the new package being added
+     * @param existing all other packages currently on the device.
+     */
+    public void addPackage(PackageParser.Package newPkg,
+            Map<String, PackageParser.Package> existing) {
+        // let's re-evaluate the ability of already added packages to see this new package
+        if (newPkg.mForceQueryable
+                || (mSystemAppsQueryable && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
+            mForceQueryable.add(newPkg.packageName);
+        } else {
+            for (String packageName : mQueriesViaIntent.keySet()) {
+                if (packageName == newPkg.packageName) {
+                    continue;
+                }
+                final PackageParser.Package existingPackage = existing.get(packageName);
+                if (canQuery(existingPackage, newPkg)) {
+                    mQueriesViaIntent.get(packageName).add(newPkg.packageName);
+                }
+            }
+        }
+        // if the new package declares them, let's evaluate its ability to see existing packages
+        mQueriesViaIntent.put(newPkg.packageName, new ArrayList<>());
+        for (PackageParser.Package existingPackage : existing.values()) {
+            if (existingPackage.packageName == newPkg.packageName) {
+                continue;
+            }
+            if (existingPackage.mForceQueryable
+                    || (mSystemAppsQueryable
+                    && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
+                continue;
+            }
+            if (canQuery(newPkg, existingPackage)) {
+                mQueriesViaIntent.get(newPkg.packageName).add(existingPackage.packageName);
+            }
+        }
+        final ArrayList<String> queriesPackages = new ArrayList<>(
+                newPkg.mQueriesPackages == null ? 0 : newPkg.mQueriesPackages.size());
+        if (newPkg.mQueriesPackages != null) {
+            queriesPackages.addAll(newPkg.mQueriesPackages);
+        }
+        mQueriesViaPackage.put(newPkg.packageName, queriesPackages);
+    }
+
+    /**
+     * Removes a package for consideration when filtering visibility between apps.
+     *
+     * @param packageName the name of the package being removed.
+     */
+    public void removePackage(String packageName) {
+        mForceQueryable.remove(packageName);
+
+        for (int i = 0; i < mImplicitlyQueryable.size(); i++) {
+            mImplicitlyQueryable.valueAt(i).remove(packageName);
+            for (ArrayList<String> initiators : mImplicitlyQueryable.valueAt(i).values()) {
+                initiators.remove(packageName);
+            }
+        }
+
+        mQueriesViaIntent.remove(packageName);
+        for (List<String> declarators : mQueriesViaIntent.values()) {
+            declarators.remove(packageName);
+        }
+
+        mQueriesViaPackage.remove(packageName);
+    }
+
+    /**
+     * Returns true if the calling package should not be able to see the target package, false if no
+     * filtering should be done.
+     *
+     * @param callingUid       the uid of the caller attempting to access a package
+     * @param callingSetting   the setting attempting to access a package or null if it could not be
+     *                         found
+     * @param targetPkgSetting the package being accessed
+     * @param userId           the user in which this access is being attempted
+     */
+    public boolean shouldFilterApplication(int callingUid, @Nullable SettingBase callingSetting,
+            PackageSetting targetPkgSetting, int userId) {
+        if (callingUid < Process.FIRST_APPLICATION_UID) {
+            return false;
+        }
+        if (callingSetting == null) {
+            Slog.wtf(TAG, "No setting found for non system uid " + callingUid);
+            return true;
+        }
+        PackageSetting callingPkgSetting = null;
+        if (callingSetting instanceof PackageSetting) {
+            callingPkgSetting = (PackageSetting) callingSetting;
+            if (!shouldFilterApplicationInternal(callingPkgSetting, targetPkgSetting,
+                    userId)) {
+                // TODO: actually base this on a start / launch (not just a query)
+                markAppInteraction(callingPkgSetting, targetPkgSetting, userId);
+                return false;
+            }
+        } else if (callingSetting instanceof SharedUserSetting) {
+            final ArraySet<PackageSetting> packageSettings =
+                    ((SharedUserSetting) callingSetting).packages;
+            if (packageSettings != null && packageSettings.size() > 0) {
+                for (PackageSetting packageSetting : packageSettings) {
+                    if (!shouldFilterApplicationInternal(packageSetting, targetPkgSetting,
+                            userId)) {
+                        // TODO: actually base this on a start / launch (not just a query)
+                        markAppInteraction(packageSetting, targetPkgSetting, userId);
+                        return false;
+                    }
+                    if (callingPkgSetting == null && packageSetting.pkg != null) {
+                        callingPkgSetting = packageSetting;
+                    }
+                }
+            } else {
+                return true;
+            }
+        }
+        if (callingPkgSetting == null) {
+            Slog.wtf(TAG, "What... " + callingSetting);
+            return true;
+        }
+        final int mode = mAppOpsManager
+                .checkOpNoThrow(AppOpsManager.OP_QUERY_ALL_PACKAGES, callingUid,
+                        callingPkgSetting.pkg.packageName);
+        switch (mode) {
+            case AppOpsManager.MODE_DEFAULT:
+                // if default, let's rely on remote feature toggle to determine whether to
+                // actually filter
+                return mConfigProvider.isEnabled();
+            case AppOpsManager.MODE_ALLOWED:
+                // explicitly allowed to see all packages, don't filter
+                return false;
+            case AppOpsManager.MODE_ERRORED:
+                // deny / error: let's log so developer can audit usages
+                Slog.i(TAG, callingPkgSetting.pkg.packageName
+                        + " blocked from accessing " + targetPkgSetting.pkg.packageName);
+            case AppOpsManager.MODE_IGNORED:
+                // fall through
+            default:
+                return true;
+        }
+    }
+
+    private boolean shouldFilterApplicationInternal(
+            PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, int userId) {
+        final String callingName = callingPkgSetting.pkg.packageName;
+        final PackageParser.Package targetPkg = targetPkgSetting.pkg;
+
+        // This package isn't technically installed and won't be written to settings, so we can
+        // treat it as filtered until it's available again.
+        if (targetPkg == null) {
+            return true;
+        }
+        final String targetName = targetPkg.packageName;
+        if (callingPkgSetting.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) {
+            return false;
+        }
+        if (isImplicitlyQueryableSystemApp(targetPkgSetting)) {
+            return false;
+        }
+        if (targetPkg.mForceQueryable) {
+            return false;
+        }
+        if (mForceQueryable.contains(targetName)) {
+            return false;
+        }
+        if (mQueriesViaPackage.containsKey(callingName)
+                && mQueriesViaPackage.get(callingName).contains(
+                targetName)) {
+            // the calling package has explicitly declared the target package; allow
+            return false;
+        } else if (mQueriesViaIntent.containsKey(callingName)
+                && mQueriesViaIntent.get(callingName).contains(targetName)) {
+            return false;
+        }
+        if (mImplicitlyQueryable.get(userId) != null
+                && mImplicitlyQueryable.get(userId).containsKey(callingName)
+                && mImplicitlyQueryable.get(userId).get(callingName).contains(targetName)) {
+            return false;
+        }
+        try {
+            if (mPermissionManager.checkPermission(
+                    Manifest.permission.QUERY_ALL_PACKAGES, callingName, userId)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return false;
+            }
+        } catch (RemoteException e) {
+            return true;
+        }
+        return true;
+    }
+
+    private boolean isImplicitlyQueryableSystemApp(PackageSetting targetPkgSetting) {
+        return targetPkgSetting.isSystem() && (mSystemAppsQueryable
+                || mForceQueryableByDevice.contains(targetPkgSetting.pkg.packageName));
+    }
+
+    public interface ConfigProvider {
+        boolean isEnabled();
+    }
+
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 2b33ace..c712431 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -281,20 +281,7 @@
         mAbortIdleOptimization.set(false);
 
         long lowStorageThreshold = getLowStorageThreshold(context);
-        // Optimize primary apks.
-        int result = optimizePackages(pm, pkgs, lowStorageThreshold,
-            /*isForPrimaryDex=*/ true);
-        if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
-            return result;
-        }
-        if (supportSecondaryDex()) {
-            result = reconcileSecondaryDexFiles(pm.getDexManager());
-            if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
-                return result;
-            }
-            result = optimizePackages(pm, pkgs, lowStorageThreshold,
-                /*isForPrimaryDex=*/ false);
-        }
+        int result = idleOptimizePackages(pm, pkgs, lowStorageThreshold);
         return result;
     }
 
@@ -342,46 +329,88 @@
         return 0;
     }
 
-    private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
-            long lowStorageThreshold, boolean isForPrimaryDex) {
+    private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+            long lowStorageThreshold) {
         ArraySet<String> updatedPackages = new ArraySet<>();
-        Set<String> unusedPackages = pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
-        boolean hadSomeLowSpaceFailure = false;
-        Log.d(TAG, "Unsused Packages " +  String.join(",", unusedPackages));
-        // Only downgrade apps when space is low on device.
-        // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
-        // up disk before user hits the actual lowStorageThreshold.
-        final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE *
-                lowStorageThreshold;
-        boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
-        Log.d(TAG, "Should Downgrade " + shouldDowngrade);
-        boolean dex_opt_performed = false;
-        for (String pkg : pkgs) {
-            int abort_code = abortIdleOptimizations(lowStorageThreshold);
-            if (abort_code == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
-                return abort_code;
-            }
-            // Downgrade unused packages.
-            if (unusedPackages.contains(pkg) && shouldDowngrade) {
-                dex_opt_performed = downgradePackage(pm, pkg, isForPrimaryDex);
-            } else {
-                if (abort_code == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
-                    // can't dexopt because of low space.
-                    hadSomeLowSpaceFailure = true;
-                    continue;
+
+        try {
+            final boolean supportSecondaryDex = supportSecondaryDex();
+
+            if (supportSecondaryDex) {
+                int result = reconcileSecondaryDexFiles(pm.getDexManager());
+                if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+                    return result;
                 }
-                dex_opt_performed = optimizePackage(pm, pkg, isForPrimaryDex);
             }
-            if (dex_opt_performed) {
+
+            // Only downgrade apps when space is low on device.
+            // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
+            // up disk before user hits the actual lowStorageThreshold.
+            final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
+                    * lowStorageThreshold;
+            boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
+            Log.d(TAG, "Should Downgrade " + shouldDowngrade);
+            if (shouldDowngrade) {
+                Set<String> unusedPackages =
+                        pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
+                Log.d(TAG, "Unsused Packages " +  String.join(",", unusedPackages));
+
+                if (!unusedPackages.isEmpty()) {
+                    for (String pkg : unusedPackages) {
+                        int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1);
+                        if (abortCode != OPTIMIZE_CONTINUE) {
+                            // Should be aborted by the scheduler.
+                            return abortCode;
+                        }
+                        if (downgradePackage(pm, pkg, /*isForPrimaryDex*/ true)) {
+                            updatedPackages.add(pkg);
+                        }
+                        if (supportSecondaryDex) {
+                            downgradePackage(pm, pkg, /*isForPrimaryDex*/ false);
+                        }
+                    }
+
+                    pkgs = new ArraySet<>(pkgs);
+                    pkgs.removeAll(unusedPackages);
+                }
+            }
+
+            int primaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
+                    /*isForPrimaryDex*/ true, updatedPackages);
+            if (primaryResult != OPTIMIZE_PROCESSED) {
+                return primaryResult;
+            }
+
+            if (!supportSecondaryDex) {
+                return OPTIMIZE_PROCESSED;
+            }
+
+            int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
+                    /*isForPrimaryDex*/ false, updatedPackages);
+            return secondaryResult;
+        } finally {
+            // Always let the pinner service know about changes.
+            notifyPinService(updatedPackages);
+        }
+    }
+
+    private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+            long lowStorageThreshold, boolean isForPrimaryDex, ArraySet<String> updatedPackages) {
+        for (String pkg : pkgs) {
+            int abortCode = abortIdleOptimizations(lowStorageThreshold);
+            if (abortCode != OPTIMIZE_CONTINUE) {
+                // Either aborted by the scheduler or no space left.
+                return abortCode;
+            }
+
+            boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex);
+            if (dexOptPerformed) {
                 updatedPackages.add(pkg);
             }
         }
-
-        notifyPinService(updatedPackages);
-        return hadSomeLowSpaceFailure ? OPTIMIZE_ABORT_NO_SPACE_LEFT : OPTIMIZE_PROCESSED;
+        return OPTIMIZE_PROCESSED;
     }
 
-
     /**
      * Try to downgrade the package to a smaller compilation filter.
      * eg. if the package is in speed-profile the package will be downgraded to verify.
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 8f38026..5eaddf9 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -686,7 +686,7 @@
 
         // Prune first installed instant apps
         synchronized (mService.mLock) {
-            allUsers = PackageManagerService.sUserManager.getUserIds();
+            allUsers = mService.mUserManager.getUserIds();
 
             final int packageCount = mService.mPackages.size();
             for (int i = 0; i < packageCount; i++) {
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index f326f1d..ec48713 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -22,11 +22,11 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 
+import dalvik.system.VMRuntime;
+
 import java.util.ArrayList;
 import java.util.List;
 
-import dalvik.system.VMRuntime;
-
 /**
  * Provides various methods for obtaining and converting of instruction sets.
  *
@@ -113,12 +113,15 @@
         return allInstructionSets;
     }
 
-    public static String getPrimaryInstructionSet(ApplicationInfo info) {
-        if (info.primaryCpuAbi == null) {
+    /**
+     * Calculates the primary instruction set based on the computed Abis of a given package.
+     */
+    public static String getPrimaryInstructionSet(PackageAbiHelper.Abis abis) {
+        if (abis.primary == null) {
             return getPreferredInstructionSet();
         }
 
-        return VMRuntime.getInstructionSet(info.primaryCpuAbi);
+        return VMRuntime.getInstructionSet(abis.primary);
     }
 
 }
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index da45582..c21d0cf 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -18,56 +18,44 @@
 
 import android.annotation.Nullable;
 import android.content.pm.PackageParser;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.File;
-import java.util.List;
 import java.util.Set;
 
 @VisibleForTesting
-interface PackageAbiHelper {
+public interface PackageAbiHelper {
     /**
-     * Derive and set the location of native libraries for the given package,
+     * Derive and get the location of native libraries for the given package,
      * which varies depending on where and how the package was installed.
-     *
-     * WARNING: This API enables modifying of the package.
-     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
      */
-    void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir);
+    NativeLibraryPaths getNativeLibraryPaths(
+            PackageParser.Package pkg, File appLib32InstallDir);
 
     /**
-     * Calculate the abis and roots for a bundled app. These can uniquely
-     * be determined from the contents of the system partition, i.e whether
-     * it contains 64 or 32 bit shared libraries etc. We do not validate any
-     * of this information, and instead assume that the system was built
-     * sensibly.
-     *
-     * WARNING: This API enables modifying of the package.
-     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
+     * Calculate the abis for a bundled app. These can uniquely be determined from the contents of
+     * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
+     * validate any of this information, and instead assume that the system was built sensibly.
      */
-    void setBundledAppAbisAndRoots(PackageParser.Package pkg,
-            PackageSetting pkgSetting);
+    Abis getBundledAppAbis(PackageParser.Package pkg);
 
     /**
-     * Derive the ABI of a non-system package located at {@code scanFile}. This information
-     * is derived purely on the basis of the contents of {@code scanFile} and
-     * {@code cpuAbiOverride}.
+     * Derive the ABI of a non-system package located at {@code pkg}. This information
+     * is derived purely on the basis of the contents of {@code pkg} and {@code cpuAbiOverride}.
      *
      * If {@code extractLibs} is true, native libraries are extracted from the app if required.
-     *
-     * WARNING: This API enables modifying of the package.
-     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
      */
-    void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
-            boolean extractLibs)
+    Pair<Abis, NativeLibraryPaths> derivePackageAbi(
+            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
             throws PackageManagerException;
 
     /**
-     * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
-     * i.e, so that all packages can be run inside a single process if required.
+     * Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
+     * match. i.e, so that all packages can be run inside a single process if required.
      *
-     * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
+     * Optionally, callers can pass in a parsed package via {@code scannedPackage} in which case
      * this function will either try and make the ABI for all packages in
      * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
      * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
@@ -76,10 +64,72 @@
      * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
      * adds unnecessary complexity.
      *
-     * WARNING: This API enables modifying of the package.
-     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
+     * @return the calculated primary abi that should be set for all non-specified packages
+     *         belonging to the shared user.
      */
     @Nullable
-    List<String> adjustCpuAbisForSharedUser(
+    String getAdjustedAbiForSharedUser(
             Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+
+    /**
+     * The native library paths and related properties that should be set on a
+     * {@link android.content.pm.PackageParser.Package}.
+     */
+    final class NativeLibraryPaths {
+        public final String nativeLibraryRootDir;
+        public final boolean nativeLibraryRootRequiresIsa;
+        public final String nativeLibraryDir;
+        public final String secondaryNativeLibraryDir;
+
+        @VisibleForTesting
+        NativeLibraryPaths(String nativeLibraryRootDir,
+                boolean nativeLibraryRootRequiresIsa, String nativeLibraryDir,
+                String secondaryNativeLibraryDir) {
+            this.nativeLibraryRootDir = nativeLibraryRootDir;
+            this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+            this.nativeLibraryDir = nativeLibraryDir;
+            this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        }
+
+        public void applyTo(PackageParser.Package pkg) {
+            pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+            pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+            pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
+            pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        }
+    }
+
+    /**
+     * The primary and secondary ABIs that should be set on a package and its package setting.
+     */
+    final class Abis {
+        public final String primary;
+        public final String secondary;
+
+        @VisibleForTesting
+        Abis(String primary, String secondary) {
+            this.primary = primary;
+            this.secondary = secondary;
+        }
+
+        Abis(PackageParser.Package pkg) {
+            this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
+        }
+
+        public void applyTo(PackageParser.Package pkg) {
+            pkg.applicationInfo.primaryCpuAbi = primary;
+            pkg.applicationInfo.secondaryCpuAbi = secondary;
+        }
+        public void applyTo(PackageSetting pkgSetting) {
+            // pkgSetting might be null during rescan following uninstall of updates
+            // to a bundled app, so accommodate that possibility.  The settings in
+            // that case will be established later from the parsed package.
+            //
+            // If the settings aren't null, sync them up with what we've derived.
+            if (pkgSetting != null) {
+                pkgSetting.primaryCpuAbiString = primary;
+                pkgSetting.secondaryCpuAbiString = secondary;
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 4ecc888..1d3d24c 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -34,6 +34,7 @@
 import android.os.FileUtils;
 import android.os.Trace;
 import android.text.TextUtils;
+import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.content.NativeLibraryHelper;
@@ -45,430 +46,10 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Set;
 
 final class PackageAbiHelperImpl implements PackageAbiHelper {
 
-    @Override
-    public void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
-        final ApplicationInfo info = pkg.applicationInfo;
-        final String codePath = pkg.codePath;
-        final File codeFile = new File(codePath);
-        final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
-
-        info.nativeLibraryRootDir = null;
-        info.nativeLibraryRootRequiresIsa = false;
-        info.nativeLibraryDir = null;
-        info.secondaryNativeLibraryDir = null;
-
-        if (isApkFile(codeFile)) {
-            // Monolithic install
-            if (bundledApp) {
-                // If "/system/lib64/apkname" exists, assume that is the per-package
-                // native library directory to use; otherwise use "/system/lib/apkname".
-                final String apkRoot = calculateBundledApkRoot(info.sourceDir);
-                final boolean is64Bit = VMRuntime.is64BitInstructionSet(
-                        getPrimaryInstructionSet(info));
-
-                // This is a bundled system app so choose the path based on the ABI.
-                // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
-                // is just the default path.
-                final String apkName = deriveCodePathName(codePath);
-                final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
-                info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
-                        apkName).getAbsolutePath();
-
-                if (info.secondaryCpuAbi != null) {
-                    final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
-                    info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
-                            secondaryLibDir, apkName).getAbsolutePath();
-                }
-            } else {
-                final String apkName = deriveCodePathName(codePath);
-                info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
-                        .getAbsolutePath();
-            }
-
-            info.nativeLibraryRootRequiresIsa = false;
-            info.nativeLibraryDir = info.nativeLibraryRootDir;
-        } else {
-            // Cluster install
-            info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
-            info.nativeLibraryRootRequiresIsa = true;
-
-            info.nativeLibraryDir = new File(info.nativeLibraryRootDir,
-                    getPrimaryInstructionSet(info)).getAbsolutePath();
-
-            if (info.secondaryCpuAbi != null) {
-                info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,
-                        VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();
-            }
-        }
-    }
-
-    @Override
-    public void setBundledAppAbisAndRoots(PackageParser.Package pkg,
-            PackageSetting pkgSetting) {
-        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
-
-        // If "/system/lib64/apkname" exists, assume that is the per-package
-        // native library directory to use; otherwise use "/system/lib/apkname".
-        final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
-        setBundledAppAbi(pkg, apkRoot, apkName);
-        // pkgSetting might be null during rescan following uninstall of updates
-        // to a bundled app, so accommodate that possibility.  The settings in
-        // that case will be established later from the parsed package.
-        //
-        // If the settings aren't null, sync them up with what we've just derived.
-        // note that apkRoot isn't stored in the package settings.
-        if (pkgSetting != null) {
-            pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
-            pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
-        }
-    }
-
-    /**
-     * Deduces the ABI of a bundled app and sets the relevant fields on the
-     * parsed pkg object.
-     *
-     * @param apkRoot the root of the installed apk, something like {@code /system} or
-     *                {@code /oem} under which system libraries are installed.
-     * @param apkName the name of the installed package.
-     */
-    private void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
-        final File codeFile = new File(pkg.codePath);
-
-        final boolean has64BitLibs;
-        final boolean has32BitLibs;
-        if (isApkFile(codeFile)) {
-            // Monolithic install
-            has64BitLibs =
-                    (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
-            has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
-        } else {
-            // Cluster install
-            final File rootDir = new File(codeFile, LIB_DIR_NAME);
-            if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
-                    && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
-                final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
-                has64BitLibs = (new File(rootDir, isa)).exists();
-            } else {
-                has64BitLibs = false;
-            }
-            if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
-                    && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
-                final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
-                has32BitLibs = (new File(rootDir, isa)).exists();
-            } else {
-                has32BitLibs = false;
-            }
-        }
-
-        if (has64BitLibs && !has32BitLibs) {
-            // The package has 64 bit libs, but not 32 bit libs. Its primary
-            // ABI should be 64 bit. We can safely assume here that the bundled
-            // native libraries correspond to the most preferred ABI in the list.
-
-            pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
-            pkg.applicationInfo.secondaryCpuAbi = null;
-        } else if (has32BitLibs && !has64BitLibs) {
-            // The package has 32 bit libs but not 64 bit libs. Its primary
-            // ABI should be 32 bit.
-
-            pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
-            pkg.applicationInfo.secondaryCpuAbi = null;
-        } else if (has32BitLibs && has64BitLibs) {
-            // The application has both 64 and 32 bit bundled libraries. We check
-            // here that the app declares multiArch support, and warn if it doesn't.
-            //
-            // We will be lenient here and record both ABIs. The primary will be the
-            // ABI that's higher on the list, i.e, a device that's configured to prefer
-            // 64 bit apps will see a 64 bit primary ABI,
-
-            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
-                Slog.e(PackageManagerService.TAG,
-                        "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
-            }
-
-            if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
-                pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
-                pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
-            } else {
-                pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
-                pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
-            }
-        } else {
-            pkg.applicationInfo.primaryCpuAbi = null;
-            pkg.applicationInfo.secondaryCpuAbi = null;
-        }
-    }
-
-    @Override
-    public void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
-            boolean extractLibs)
-            throws PackageManagerException {
-        // Give ourselves some initial paths; we'll come back for another
-        // pass once we've determined ABI below.
-        setNativeLibraryPaths(pkg, PackageManagerService.sAppLib32InstallDir);
-
-        // We shouldn't attempt to extract libs from system app when it was not updated.
-        if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
-            extractLibs = false;
-        }
-
-        final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
-        final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
-
-        NativeLibraryHelper.Handle handle = null;
-        try {
-            handle = NativeLibraryHelper.Handle.create(pkg);
-            // TODO(multiArch): This can be null for apps that didn't go through the
-            // usual installation process. We can calculate it again, like we
-            // do during install time.
-            //
-            // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
-            // unnecessary.
-            final File nativeLibraryRoot = new File(nativeLibraryRootStr);
-
-            // Null out the abis so that they can be recalculated.
-            pkg.applicationInfo.primaryCpuAbi = null;
-            pkg.applicationInfo.secondaryCpuAbi = null;
-            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
-                // Warn if we've set an abiOverride for multi-lib packages..
-                // By definition, we need to copy both 32 and 64 bit libraries for
-                // such packages.
-                if (pkg.cpuAbiOverride != null
-                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
-                    Slog.w(PackageManagerService.TAG,
-                            "Ignoring abiOverride for multi arch application.");
-                }
-
-                int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
-                int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
-                if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
-                    if (extractLibs) {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                        abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
-                                useIsaSpecificSubdirs);
-                    } else {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
-                        abi32 = NativeLibraryHelper.findSupportedAbi(
-                                handle, Build.SUPPORTED_32_BIT_ABIS);
-                    }
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-
-                // Shared library native code should be in the APK zip aligned
-                if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
-                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                            "Shared library native lib extraction not supported");
-                }
-
-                maybeThrowExceptionForMultiArchCopy(
-                        "Error unpackaging 32 bit native libs for multiarch app.", abi32);
-
-                if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
-                    if (extractLibs) {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                        abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
-                                useIsaSpecificSubdirs);
-                    } else {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
-                        abi64 = NativeLibraryHelper.findSupportedAbi(
-                                handle, Build.SUPPORTED_64_BIT_ABIS);
-                    }
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-
-                maybeThrowExceptionForMultiArchCopy(
-                        "Error unpackaging 64 bit native libs for multiarch app.", abi64);
-
-                if (abi64 >= 0) {
-                    // Shared library native libs should be in the APK zip aligned
-                    if (extractLibs && pkg.isLibrary()) {
-                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                                "Shared library native lib extraction not supported");
-                    }
-                    pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
-                }
-
-                if (abi32 >= 0) {
-                    final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
-                    if (abi64 >= 0) {
-                        if (pkg.use32bitAbi) {
-                            pkg.applicationInfo.secondaryCpuAbi =
-                                    pkg.applicationInfo.primaryCpuAbi;
-                            pkg.applicationInfo.primaryCpuAbi = abi;
-                        } else {
-                            pkg.applicationInfo.secondaryCpuAbi = abi;
-                        }
-                    } else {
-                        pkg.applicationInfo.primaryCpuAbi = abi;
-                    }
-                }
-            } else {
-                String[] abiList = (cpuAbiOverride != null)
-                        ? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
-
-                // Enable gross and lame hacks for apps that are built with old
-                // SDK tools. We must scan their APKs for renderscript bitcode and
-                // not launch them if it's present. Don't bother checking on devices
-                // that don't have 64 bit support.
-                boolean needsRenderScriptOverride = false;
-                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
-                        && NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
-                    abiList = Build.SUPPORTED_32_BIT_ABIS;
-                    needsRenderScriptOverride = true;
-                }
-
-                final int copyRet;
-                if (extractLibs) {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                    copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                            nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
-                } else {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
-                    copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
-                }
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
-                if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
-                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                            "Error unpackaging native libs for app, errorCode=" + copyRet);
-                }
-
-                if (copyRet >= 0) {
-                    // Shared libraries that have native libs must be multi-architecture
-                    if (pkg.isLibrary()) {
-                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                                "Shared library with native libs must be multiarch");
-                    }
-                    pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
-                } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES
-                        && cpuAbiOverride != null) {
-                    pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
-                } else if (needsRenderScriptOverride) {
-                    pkg.applicationInfo.primaryCpuAbi = abiList[0];
-                }
-            }
-        } catch (IOException ioe) {
-            Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString());
-        } finally {
-            IoUtils.closeQuietly(handle);
-        }
-
-        // Now that we've calculated the ABIs and determined if it's an internal app,
-        // we will go ahead and populate the nativeLibraryPath.
-        setNativeLibraryPaths(pkg, PackageManagerService.sAppLib32InstallDir);
-    }
-
-    /**
-     * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
-     * i.e, so that all packages can be run inside a single process if required.
-     *
-     * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
-     * this function will either try and make the ABI for all packages in
-     * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
-     * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
-     * variant is used when installing or updating a package that belongs to a shared user.
-     *
-     * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
-     * adds unnecessary complexity.
-     */
-    @Override
-    @Nullable
-    public List<String> adjustCpuAbisForSharedUser(
-            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
-        List<String> changedAbiCodePath = null;
-        String requiredInstructionSet = null;
-        if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
-            requiredInstructionSet = VMRuntime.getInstructionSet(
-                    scannedPackage.applicationInfo.primaryCpuAbi);
-        }
-
-        PackageSetting requirer = null;
-        for (PackageSetting ps : packagesForUser) {
-            // If packagesForUser contains scannedPackage, we skip it. This will happen
-            // when scannedPackage is an update of an existing package. Without this check,
-            // we will never be able to change the ABI of any package belonging to a shared
-            // user, even if it's compatible with other packages.
-            if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
-                if (ps.primaryCpuAbiString == null) {
-                    continue;
-                }
-
-                final String instructionSet =
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
-                if (requiredInstructionSet != null
-                        && !instructionSet.equals(requiredInstructionSet)) {
-                    // We have a mismatch between instruction sets (say arm vs arm64) warn about
-                    // this but there's not much we can do.
-                    String errorMessage = "Instruction set mismatch, "
-                            + ((requirer == null) ? "[caller]" : requirer)
-                            + " requires " + requiredInstructionSet + " whereas " + ps
-                            + " requires " + instructionSet;
-                    Slog.w(PackageManagerService.TAG, errorMessage);
-                }
-
-                if (requiredInstructionSet == null) {
-                    requiredInstructionSet = instructionSet;
-                    requirer = ps;
-                }
-            }
-        }
-
-        if (requiredInstructionSet != null) {
-            String adjustedAbi;
-            if (requirer != null) {
-                // requirer != null implies that either scannedPackage was null or that
-                // scannedPackage did not require an ABI, in which case we have to adjust
-                // scannedPackage to match the ABI of the set (which is the same as
-                // requirer's ABI)
-                adjustedAbi = requirer.primaryCpuAbiString;
-                if (scannedPackage != null) {
-                    scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
-                }
-            } else {
-                // requirer == null implies that we're updating all ABIs in the set to
-                // match scannedPackage.
-                adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
-            }
-
-            for (PackageSetting ps : packagesForUser) {
-                if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
-                    if (ps.primaryCpuAbiString != null) {
-                        continue;
-                    }
-
-                    ps.primaryCpuAbiString = adjustedAbi;
-                    if (ps.pkg != null && ps.pkg.applicationInfo != null
-                            && !TextUtils.equals(
-                            adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
-                        ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
-                        if (PackageManagerService.DEBUG_ABI_SELECTION) {
-                            Slog.i(PackageManagerService.TAG,
-                                    "Adjusting ABI for " + ps.name + " to " + adjustedAbi
-                                            + " (requirer="
-                                            + (requirer != null ? requirer.pkg : "null")
-                                            + ", scannedPackage="
-                                            + (scannedPackage != null ? scannedPackage : "null")
-                                            + ")");
-                        }
-                        if (changedAbiCodePath == null) {
-                            changedAbiCodePath = new ArrayList<>();
-                        }
-                        changedAbiCodePath.add(ps.codePathString);
-                    }
-                }
-            }
-        }
-        return changedAbiCodePath;
-    }
-
     private static String calculateBundledApkRoot(final String codePathString) {
         final File codePath = new File(codePathString);
         final File codeRoot;
@@ -539,4 +120,409 @@
         }
     }
 
+    @Override
+    public NativeLibraryPaths getNativeLibraryPaths(
+            PackageParser.Package pkg, File appLib32InstallDir) {
+        return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath,
+                pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
+                pkg.applicationInfo.isUpdatedSystemApp());
+    }
+
+    private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
+            final File appLib32InstallDir, final String codePath, final String sourceDir,
+            final boolean isSystemApp, final boolean isUpdatedSystemApp) {
+        final File codeFile = new File(codePath);
+        final boolean bundledApp = isSystemApp && !isUpdatedSystemApp;
+
+        final String nativeLibraryRootDir;
+        final boolean nativeLibraryRootRequiresIsa;
+        final String nativeLibraryDir;
+        final String secondaryNativeLibraryDir;
+
+        if (isApkFile(codeFile)) {
+            // Monolithic install
+            if (bundledApp) {
+                // If "/system/lib64/apkname" exists, assume that is the per-package
+                // native library directory to use; otherwise use "/system/lib/apkname".
+                final String apkRoot = calculateBundledApkRoot(sourceDir);
+                final boolean is64Bit = VMRuntime.is64BitInstructionSet(
+                        getPrimaryInstructionSet(abis));
+
+                // This is a bundled system app so choose the path based on the ABI.
+                // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
+                // is just the default path.
+                final String apkName = deriveCodePathName(codePath);
+                final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
+                nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
+                        apkName).getAbsolutePath();
+
+                if (abis.secondary != null) {
+                    final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
+                    secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
+                            secondaryLibDir, apkName).getAbsolutePath();
+                } else {
+                    secondaryNativeLibraryDir = null;
+                }
+            } else {
+                final String apkName = deriveCodePathName(codePath);
+                nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
+                        .getAbsolutePath();
+                secondaryNativeLibraryDir = null;
+            }
+
+            nativeLibraryRootRequiresIsa = false;
+            nativeLibraryDir = nativeLibraryRootDir;
+        } else {
+            // Cluster install
+            nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
+            nativeLibraryRootRequiresIsa = true;
+
+            nativeLibraryDir = new File(nativeLibraryRootDir,
+                    getPrimaryInstructionSet(abis)).getAbsolutePath();
+
+            if (abis.secondary != null) {
+                secondaryNativeLibraryDir = new File(nativeLibraryRootDir,
+                        VMRuntime.getInstructionSet(abis.secondary)).getAbsolutePath();
+            } else {
+                secondaryNativeLibraryDir = null;
+            }
+        }
+        return new NativeLibraryPaths(nativeLibraryRootDir, nativeLibraryRootRequiresIsa,
+                nativeLibraryDir, secondaryNativeLibraryDir);
+    }
+
+    @Override
+    public Abis getBundledAppAbis(PackageParser.Package pkg) {
+        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+
+        // If "/system/lib64/apkname" exists, assume that is the per-package
+        // native library directory to use; otherwise use "/system/lib/apkname".
+        final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+        final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
+        return abis;
+    }
+
+    /**
+     * Deduces the ABI of a bundled app and sets the relevant fields on the
+     * parsed pkg object.
+     *
+     * @param apkRoot the root of the installed apk, something like {@code /system} or
+     *                {@code /oem} under which system libraries are installed.
+     * @param apkName the name of the installed package.
+     */
+    private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
+        final File codeFile = new File(pkg.codePath);
+
+        final boolean has64BitLibs;
+        final boolean has32BitLibs;
+
+        final String primaryCpuAbi;
+        final String secondaryCpuAbi;
+        if (isApkFile(codeFile)) {
+            // Monolithic install
+            has64BitLibs =
+                    (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
+            has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
+        } else {
+            // Cluster install
+            final File rootDir = new File(codeFile, LIB_DIR_NAME);
+            if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
+                    && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
+                final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
+                has64BitLibs = (new File(rootDir, isa)).exists();
+            } else {
+                has64BitLibs = false;
+            }
+            if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
+                    && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
+                final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
+                has32BitLibs = (new File(rootDir, isa)).exists();
+            } else {
+                has32BitLibs = false;
+            }
+        }
+
+        if (has64BitLibs && !has32BitLibs) {
+            // The package has 64 bit libs, but not 32 bit libs. Its primary
+            // ABI should be 64 bit. We can safely assume here that the bundled
+            // native libraries correspond to the most preferred ABI in the list.
+
+            primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+            secondaryCpuAbi = null;
+        } else if (has32BitLibs && !has64BitLibs) {
+            // The package has 32 bit libs but not 64 bit libs. Its primary
+            // ABI should be 32 bit.
+
+            primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+            secondaryCpuAbi = null;
+        } else if (has32BitLibs && has64BitLibs) {
+            // The application has both 64 and 32 bit bundled libraries. We check
+            // here that the app declares multiArch support, and warn if it doesn't.
+            //
+            // We will be lenient here and record both ABIs. The primary will be the
+            // ABI that's higher on the list, i.e, a device that's configured to prefer
+            // 64 bit apps will see a 64 bit primary ABI,
+
+            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+                Slog.e(PackageManagerService.TAG,
+                        "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
+            }
+
+            if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
+                primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+                secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+            } else {
+                primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+                secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+            }
+        } else {
+            primaryCpuAbi = null;
+            secondaryCpuAbi = null;
+        }
+        return new Abis(primaryCpuAbi, secondaryCpuAbi);
+    }
+
+    @Override
+    public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
+            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+            throws PackageManagerException {
+        // Give ourselves some initial paths; we'll come back for another
+        // pass once we've determined ABI below.
+        final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
+                PackageManagerService.sAppLib32InstallDir, pkg.codePath,
+                pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
+                pkg.applicationInfo.isUpdatedSystemApp());
+
+        // We shouldn't attempt to extract libs from system app when it was not updated.
+        if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
+            extractLibs = false;
+        }
+
+        final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
+        final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
+
+        String primaryCpuAbi = null;
+        String secondaryCpuAbi = null;
+
+        NativeLibraryHelper.Handle handle = null;
+        try {
+            handle = NativeLibraryHelper.Handle.create(pkg);
+            // TODO(multiArch): This can be null for apps that didn't go through the
+            // usual installation process. We can calculate it again, like we
+            // do during install time.
+            //
+            // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
+            // unnecessary.
+            final File nativeLibraryRoot = new File(nativeLibraryRootStr);
+
+            // Null out the abis so that they can be recalculated.
+            primaryCpuAbi = null;
+            secondaryCpuAbi = null;
+            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
+                // Warn if we've set an abiOverride for multi-lib packages..
+                // By definition, we need to copy both 32 and 64 bit libraries for
+                // such packages.
+                if (pkg.cpuAbiOverride != null
+                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+                    Slog.w(PackageManagerService.TAG,
+                            "Ignoring abiOverride for multi arch application.");
+                }
+
+                int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
+                int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
+                if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+                    if (extractLibs) {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                        abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+                                useIsaSpecificSubdirs);
+                    } else {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+                        abi32 = NativeLibraryHelper.findSupportedAbi(
+                                handle, Build.SUPPORTED_32_BIT_ABIS);
+                    }
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+
+                // Shared library native code should be in the APK zip aligned
+                if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Shared library native lib extraction not supported");
+                }
+
+                maybeThrowExceptionForMultiArchCopy(
+                        "Error unpackaging 32 bit native libs for multiarch app.", abi32);
+
+                if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+                    if (extractLibs) {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                        abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+                                useIsaSpecificSubdirs);
+                    } else {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+                        abi64 = NativeLibraryHelper.findSupportedAbi(
+                                handle, Build.SUPPORTED_64_BIT_ABIS);
+                    }
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+
+                maybeThrowExceptionForMultiArchCopy(
+                        "Error unpackaging 64 bit native libs for multiarch app.", abi64);
+
+                if (abi64 >= 0) {
+                    // Shared library native libs should be in the APK zip aligned
+                    if (extractLibs && pkg.isLibrary()) {
+                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                                "Shared library native lib extraction not supported");
+                    }
+                    primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+                }
+
+                if (abi32 >= 0) {
+                    final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+                    if (abi64 >= 0) {
+                        if (pkg.use32bitAbi) {
+                            secondaryCpuAbi = primaryCpuAbi;
+                            primaryCpuAbi = abi;
+                        } else {
+                            secondaryCpuAbi = abi;
+                        }
+                    } else {
+                        primaryCpuAbi = abi;
+                    }
+                }
+            } else {
+                String[] abiList = (cpuAbiOverride != null)
+                        ? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
+
+                // Enable gross and lame hacks for apps that are built with old
+                // SDK tools. We must scan their APKs for renderscript bitcode and
+                // not launch them if it's present. Don't bother checking on devices
+                // that don't have 64 bit support.
+                boolean needsRenderScriptOverride = false;
+                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
+                        && NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+                    abiList = Build.SUPPORTED_32_BIT_ABIS;
+                    needsRenderScriptOverride = true;
+                }
+
+                final int copyRet;
+                if (extractLibs) {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                    copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                            nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+                } else {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+                    copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+                }
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+                if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Error unpackaging native libs for app, errorCode=" + copyRet);
+                }
+
+                if (copyRet >= 0) {
+                    // Shared libraries that have native libs must be multi-architecture
+                    if (pkg.isLibrary()) {
+                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                                "Shared library with native libs must be multiarch");
+                    }
+                    primaryCpuAbi = abiList[copyRet];
+                } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES
+                        && cpuAbiOverride != null) {
+                    primaryCpuAbi = cpuAbiOverride;
+                } else if (needsRenderScriptOverride) {
+                    primaryCpuAbi = abiList[0];
+                }
+            }
+        } catch (IOException ioe) {
+            Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString());
+        } finally {
+            IoUtils.closeQuietly(handle);
+        }
+
+        // Now that we've calculated the ABIs and determined if it's an internal app,
+        // we will go ahead and populate the nativeLibraryPath.
+
+        final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
+        return new Pair<>(abis,
+                getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
+                        pkg.codePath, pkg.applicationInfo.sourceDir,
+                        pkg.applicationInfo.isSystemApp(),
+                        pkg.applicationInfo.isUpdatedSystemApp()));
+    }
+
+    /**
+     * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
+     * i.e, so that all packages can be run inside a single process if required.
+     *
+     * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
+     * this function will either try and make the ABI for all packages in
+     * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+     * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+     * variant is used when installing or updating a package that belongs to a shared user.
+     *
+     * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+     * adds unnecessary complexity.
+     */
+    @Override
+    @Nullable
+    public String getAdjustedAbiForSharedUser(
+            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+        String requiredInstructionSet = null;
+        if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
+            requiredInstructionSet = VMRuntime.getInstructionSet(
+                    scannedPackage.applicationInfo.primaryCpuAbi);
+        }
+
+        PackageSetting requirer = null;
+        for (PackageSetting ps : packagesForUser) {
+            // If packagesForUser contains scannedPackage, we skip it. This will happen
+            // when scannedPackage is an update of an existing package. Without this check,
+            // we will never be able to change the ABI of any package belonging to a shared
+            // user, even if it's compatible with other packages.
+            if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) {
+                continue;
+            }
+            if (ps.primaryCpuAbiString == null) {
+                continue;
+            }
+
+            final String instructionSet =
+                    VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
+            if (requiredInstructionSet != null && !requiredInstructionSet.equals(instructionSet)) {
+                // We have a mismatch between instruction sets (say arm vs arm64) warn about
+                // this but there's not much we can do.
+                String errorMessage = "Instruction set mismatch, "
+                        + ((requirer == null) ? "[caller]" : requirer)
+                        + " requires " + requiredInstructionSet + " whereas " + ps
+                        + " requires " + instructionSet;
+                Slog.w(PackageManagerService.TAG, errorMessage);
+            }
+
+            if (requiredInstructionSet == null) {
+                requiredInstructionSet = instructionSet;
+                requirer = ps;
+            }
+        }
+
+        if (requiredInstructionSet == null) {
+            return null;
+        }
+        final String adjustedAbi;
+        if (requirer != null) {
+            // requirer != null implies that either scannedPackage was null or that
+            // scannedPackage did not require an ABI, in which case we have to adjust
+            // scannedPackage to match the ABI of the set (which is the same as
+            // requirer's ABI)
+            adjustedAbi = requirer.primaryCpuAbiString;
+        } else {
+            // requirer == null implies that we're updating all ABIs in the set to
+            // match scannedPackage.
+            adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
+        }
+        return adjustedAbi;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0d1b9c6..89ddc15 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -92,6 +92,7 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
 import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
@@ -117,7 +118,6 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
 import android.app.IActivityManager;
@@ -313,6 +313,7 @@
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.pm.permission.PermissionsState;
+import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.security.VerityUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.utils.TimingsTraceAndSlog;
@@ -661,7 +662,7 @@
     // Lock for state used when installing and doing other long running
     // operations.  Methods that must be called with this lock held have
     // the suffix "LI".
-    final Object mInstallLock = new Object();
+    final Object mInstallLock;
 
     // ----------------------------------------------------------------
 
@@ -695,6 +696,9 @@
      */
     boolean mPromoteSystemApps;
 
+    private final PackageManagerInternal mPmInternal;
+
+
     @GuardedBy("mLock")
     final Settings mSettings;
 
@@ -750,27 +754,199 @@
     private final Injector mInjector;
 
     /**
-     * Unit tests will instantiate and / or extend to mock dependencies / behaviors.
+     * Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors.
+     *
+     * NOTE: All getters should return the same instance for every call.
      */
-    @VisibleForTesting
-    static class Injector {
-        private final UserManagerInternal mUserManager;
-        private final PackageAbiHelper mAbiHelper;
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static class Injector {
 
-        Injector(UserManagerInternal userManager, PackageAbiHelper abiHelper) {
-            mUserManager = userManager;
-            mAbiHelper = abiHelper;
+        @VisibleForTesting(visibility = Visibility.PRIVATE)
+        interface Producer<T> {
+            /** Produce an instance of type {@link T} */
+            T produce(Injector injector, PackageManagerService packageManager);
         }
 
-        public UserManagerInternal getUserManager() {
-            return mUserManager;
+        static class LocalServicesProducer<T> implements Producer<T> {
+            private final Class<T> mProducingClass;
+            LocalServicesProducer(Class<T> clazz) {
+                this.mProducingClass = clazz;
+            }
+            public T produce(Injector injector, PackageManagerService packageManager) {
+                return LocalServices.getService(mProducingClass);
+            }
+        }
+
+        static class SystemServiceProducer<T> implements Producer<T> {
+            private final Class<T> mProducingClass;
+            SystemServiceProducer(Class<T> clazz) {
+                this.mProducingClass = clazz;
+            }
+            public T produce(Injector injector, PackageManagerService packageManager) {
+                return packageManager.mContext.getSystemService(mProducingClass);
+            }
+        }
+
+        @VisibleForTesting(visibility = Visibility.PRIVATE)
+        static class Singleton<T> {
+            private final Producer<T> mProducer;
+            private volatile T mInstance = null;
+            Singleton(Producer<T> producer) {
+                this.mProducer = producer;
+            }
+            T get(Injector injector, PackageManagerService packageManagerService) {
+                if (mInstance == null) {
+                    mInstance = mProducer.produce(injector, packageManagerService);
+                }
+                return mInstance;
+            }
+        }
+
+        private PackageManagerService mPackageManager;
+
+        private final PackageAbiHelper mAbiHelper;
+        private final Context mContext;
+        private final Object mLock;
+        private final Installer mInstaller;
+        private final Object mInstallLock;
+
+        // ----- producers -----
+        private final Singleton<ComponentResolver> mComponentResolverProducer;
+        private final Singleton<PermissionManagerServiceInternal> mPermissionManagerProducer;
+        private final Singleton<UserManagerService> mUserManagerProducer;
+        private final Singleton<Settings> mSettingsProducer;
+        private final Singleton<ActivityTaskManagerInternal> mActivityTaskManagerProducer;
+        private final Singleton<DeviceIdleController.LocalService> mLocalDeviceIdleController;
+        private final Singleton<StorageManagerInternal> mStorageManagerInternalProducer;
+        private final Singleton<NetworkPolicyManagerInternal> mNetworkPolicyManagerProducer;
+        private final Singleton<PermissionPolicyInternal> mPermissionPolicyProducer;
+        private final Singleton<DeviceStorageMonitorInternal> mDeviceStorageMonitorProducer;
+        private final Singleton<DisplayManager> mDisplayManagerProducer;
+        private final Singleton<StorageManager> mStorageManagerProducer;
+        private final Singleton<AppOpsManager> mAppOpsManagerProducer;
+
+        Injector(Context context, Object lock, Installer installer,
+                Object installLock, PackageAbiHelper abiHelper,
+                Producer<ComponentResolver> componentResolverProducer,
+                Producer<PermissionManagerServiceInternal> permissionManagerProducer,
+                Producer<UserManagerService> userManagerProducer,
+                Producer<Settings> settingsProducer,
+                Producer<ActivityTaskManagerInternal> activityTaskManagerProducer,
+                Producer<DeviceIdleController.LocalService> deviceIdleControllerProducer,
+                Producer<StorageManagerInternal> storageManagerInternalProducer,
+                Producer<NetworkPolicyManagerInternal> networkPolicyManagerProducer,
+                Producer<PermissionPolicyInternal> permissionPolicyProvider,
+                Producer<DeviceStorageMonitorInternal> deviceStorageMonitorProducer,
+                Producer<DisplayManager> displayManagerProducer,
+                Producer<StorageManager> storageManagerProducer,
+                Producer<AppOpsManager> appOpsManagerProducer) {
+            mContext = context;
+            mLock = lock;
+            mInstaller = installer;
+            mAbiHelper = abiHelper;
+            mInstallLock = installLock;
+            mComponentResolverProducer = new Singleton<>(componentResolverProducer);
+            mPermissionManagerProducer = new Singleton<>(permissionManagerProducer);
+            mUserManagerProducer = new Singleton<>(userManagerProducer);
+            mSettingsProducer = new Singleton<>(settingsProducer);
+            mActivityTaskManagerProducer = new Singleton<>(activityTaskManagerProducer);
+            mLocalDeviceIdleController = new Singleton<>(deviceIdleControllerProducer);
+            mStorageManagerInternalProducer = new Singleton<>(storageManagerInternalProducer);
+            mNetworkPolicyManagerProducer = new Singleton<>(networkPolicyManagerProducer);
+            mPermissionPolicyProducer = new Singleton<>(permissionPolicyProvider);
+            mDeviceStorageMonitorProducer = new Singleton<>(deviceStorageMonitorProducer);
+            mDisplayManagerProducer = new Singleton<>(displayManagerProducer);
+            mStorageManagerProducer = new Singleton<>(storageManagerProducer);
+            mAppOpsManagerProducer = new Singleton<>(appOpsManagerProducer);
+        }
+
+        /**
+         * Bootstraps this injector with the {@link PackageManagerService instance to which it
+         * belongs.
+         */
+        public void bootstrap(PackageManagerService pm) {
+            this.mPackageManager = pm;
+        }
+
+        public UserManagerInternal getUserManagerInternal() {
+            return getUserManagerService().getInternalForInjectorOnly();
         }
 
         public PackageAbiHelper getAbiHelper() {
             return mAbiHelper;
         }
+
+        public Object getInstallLock() {
+            return mInstallLock;
+        }
+
+        public UserManagerService getUserManagerService() {
+            return mUserManagerProducer.get(this, mPackageManager);
+        }
+
+        public Object getLock() {
+            return mLock;
+        }
+
+        public Installer getInstaller() {
+            return mInstaller;
+        }
+
+        public ComponentResolver getComponentResolver() {
+            return mComponentResolverProducer.get(this, mPackageManager);
+        }
+
+        public PermissionManagerServiceInternal getPermissionManagerServiceInternal() {
+            return mPermissionManagerProducer.get(this, mPackageManager);
+        }
+
+        public Context getContext() {
+            return mContext;
+        }
+
+        public Settings getSettings() {
+            return mSettingsProducer.get(this, mPackageManager);
+        }
+
+        public ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+            return mActivityTaskManagerProducer.get(this, mPackageManager);
+        }
+
+        public DeviceIdleController.LocalService getLocalDeviceIdleController() {
+            return mLocalDeviceIdleController.get(this, mPackageManager);
+        }
+
+        public StorageManagerInternal getStorageManagerInternal() {
+            return mStorageManagerInternalProducer.get(this, mPackageManager);
+        }
+
+        public NetworkPolicyManagerInternal getNetworkPolicyManagerInternal() {
+            return mNetworkPolicyManagerProducer.get(this, mPackageManager);
+        }
+
+        public PermissionPolicyInternal getPermissionPolicyInternal() {
+            return mPermissionPolicyProducer.get(this, mPackageManager);
+        }
+
+        public DeviceStorageMonitorInternal getDeviceStorageMonitorInternal() {
+            return mDeviceStorageMonitorProducer.get(this, mPackageManager);
+        }
+
+        public DisplayManager getDisplayManager() {
+            return mDisplayManagerProducer.get(this, mPackageManager);
+        }
+
+        public StorageManager getStorageManager() {
+            return mStorageManagerProducer.get(this, mPackageManager);
+        }
+
+        public AppOpsManager getAppOpsManager() {
+            return mAppOpsManagerProducer.get(this, mPackageManager);
+        }
     }
 
+    private final AppsFilter mAppsFilter;
+
     class PackageParserCallback implements PackageParser.Callback {
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -983,13 +1159,6 @@
     // List of packages names to keep cached, even if they are uninstalled for all users
     private List<String> mKeepUninstalledPackages;
 
-    private UserManagerInternal mUserManagerInternal;
-    private ActivityManagerInternal mActivityManagerInternal;
-    private ActivityTaskManagerInternal mActivityTaskManagerInternal;
-    private StorageManagerInternal mStorageManagerInternal;
-
-    private DeviceIdleController.LocalService mDeviceIdleController;
-
     private File mCacheDir;
 
     private Future<?> mPrepareAppDataFuture;
@@ -1080,7 +1249,8 @@
             final BroadcastOptions options = BroadcastOptions.makeBasic();
             options.setTemporaryAppWhitelistDuration(whitelistTimeout);
 
-            DeviceIdleController.LocalService idleController = getDeviceIdleController();
+            DeviceIdleController.LocalService idleController =
+                    mInjector.getLocalDeviceIdleController();
             idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                     mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
                     UserHandle.USER_SYSTEM, true, "intent filter verifier");
@@ -1347,7 +1517,7 @@
     private static final long DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD =
             2 * 60 * 60 * 1000L; /* two hours */
 
-    static UserManagerService sUserManager;
+    UserManagerService mUserManager;
 
     // Stores a list of users whose package restrictions file needs to be updated
     private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
@@ -1944,8 +2114,7 @@
                 // Send broadcast package appeared if external for all users
                 if (isExternal(res.pkg)) {
                     if (!update) {
-                        final StorageManager storage =
-                                mContext.getSystemService(StorageManager.class);
+                        final StorageManager storage = mInjector.getStorageManager();
                         VolumeInfo volume =
                                 storage.findVolumeByUuid(
                                         res.pkg.applicationInfo.storageUuid.toString());
@@ -2057,7 +2226,8 @@
 
         for (String packageName : packages) {
             PackageSetting setting = mSettings.mPackages.get(packageName);
-            if (setting != null && filterAppAccessLPr(setting, callingUid, callingUserId)) {
+            if (setting != null
+                    && shouldFilterApplicationLocked(setting, callingUid, callingUserId)) {
                 notifyInstallObserver(packageName);
             }
         }
@@ -2135,7 +2305,7 @@
 
                     // Clean up any users or apps that were removed or recreated
                     // while this volume was missing
-                    sUserManager.reconcileUsers(volumeUuid);
+                    mUserManager.reconcileUsers(volumeUuid);
                     reconcileApps(volumeUuid);
 
                     // Clean up any install sessions that expired or were
@@ -2220,9 +2390,9 @@
 
     void scheduleWritePackageRestrictionsLocked(int userId) {
         final int[] userIds = (userId == UserHandle.USER_ALL)
-                ? sUserManager.getUserIds() : new int[]{userId};
+                ? mUserManager.getUserIds() : new int[]{userId};
         for (int nextUserId : userIds) {
-            if (!sUserManager.exists(nextUserId)) return;
+            if (!mUserManager.exists(nextUserId)) return;
             mDirtyUsers.add(nextUserId);
             if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
                 mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
@@ -2234,10 +2404,39 @@
             boolean factoryTest, boolean onlyCore) {
         // Self-check for initial settings.
         PackageManagerServiceCompilerMapping.checkProperties();
-        final Object packageLock = new Object();
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
+                Trace.TRACE_TAG_PACKAGE_MANAGER);
+        t.traceBegin("create package manager");
+        final Object lock = new Object();
+        final Object installLock = new Object();
 
-        PackageManagerService m = new PackageManagerService(context, installer,
-                factoryTest, onlyCore, packageLock);
+        Injector injector = new Injector(
+                context, lock, installer, installLock, new PackageAbiHelperImpl(),
+                (i, pm) ->
+                        new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
+                (i, pm) ->
+                        PermissionManagerService.create(context, lock),
+                (i, pm) ->
+                        new UserManagerService(context, pm,
+                                new UserDataPreparer(installer, installLock, context, onlyCore),
+                                lock),
+                (i, pm) ->
+                        new Settings(Environment.getDataDirectory(),
+                                i.getPermissionManagerServiceInternal().getPermissionSettings(),
+                                lock),
+                new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
+                new Injector.LocalServicesProducer<>(DeviceIdleController.LocalService.class),
+                new Injector.LocalServicesProducer<>(StorageManagerInternal.class),
+                new Injector.LocalServicesProducer<>(NetworkPolicyManagerInternal.class),
+                new Injector.LocalServicesProducer<>(PermissionPolicyInternal.class),
+                new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class),
+                new Injector.SystemServiceProducer<>(DisplayManager.class),
+                new Injector.SystemServiceProducer<>(StorageManager.class),
+                new Injector.SystemServiceProducer<>(AppOpsManager.class));
+
+        PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore);
+        t.traceEnd(); // "create package manager"
+
         m.enableSystemUserPackages();
         ServiceManager.addService("package", m);
         final PackageManagerNative pmn = m.new PackageManagerNative();
@@ -2289,9 +2488,8 @@
         }
     }
 
-    private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
-        DisplayManager displayManager = (DisplayManager) context.getSystemService(
-                Context.DISPLAY_SERVICE);
+    private static void getDefaultDisplayMetrics(
+            DisplayManager displayManager, DisplayMetrics metrics) {
         displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
     }
 
@@ -2328,12 +2526,13 @@
         }
     }
 
-    public PackageManagerService(Context context, Installer installer, boolean factoryTest,
-            boolean onlyCore, Object packageLock) {
+    public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
         final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
                 Trace.TRACE_TAG_PACKAGE_MANAGER);
-        t.traceBegin("create package manager");
-        mLock = packageLock;
+        mInjector = injector;
+        mInjector.bootstrap(this);
+        mLock = injector.getLock();
+        mInstallLock = injector.getInstallLock();
         LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                 SystemClock.uptimeMillis());
@@ -2342,38 +2541,24 @@
             Slog.w(TAG, "**** ro.build.version.sdk not set!");
         }
 
-        mContext = context;
+        mContext = injector.getContext();
         mFactoryTest = factoryTest;
         mOnlyCore = onlyCore;
         mMetrics = new DisplayMetrics();
-        mInstaller = installer;
+        mInstaller = injector.getInstaller();
 
         // Create sub-components that provide services / data. Order here is important.
         t.traceBegin("createSubComponents");
-        // CHECKSTYLE:OFF IndentationCheck
-        synchronized (mInstallLock) {
-        synchronized (mLock) {
-            // Expose private service for system components to use.
-            LocalServices.addService(
-                    PackageManagerInternal.class, new PackageManagerInternalImpl());
-            sUserManager = new UserManagerService(context, this,
-                    new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore),
-                    mLock);
-            mComponentResolver = new ComponentResolver(sUserManager,
-                    LocalServices.getService(PackageManagerInternal.class),
-                    mLock);
-            mPermissionManager = PermissionManagerService.create(context,
-                    mLock /*externalLock*/);
-            mPermissionManagerService =
-                    (IPermissionManager) ServiceManager.getService("permissionmgr");
-            mSettings = new Settings(Environment.getDataDirectory(),
-                    mPermissionManager.getPermissionSettings(), mLock);
-        }
-        }
 
-        // TODO(b/137961986): We should pass this via constructor, but would first need to create
-        // a packages lock that could also be passed in.
-        mInjector = new Injector(getUserManagerInternal(), new PackageAbiHelperImpl());
+        // Expose private service for system components to use.
+        mPmInternal = new PackageManagerInternalImpl();
+        LocalServices.addService(PackageManagerInternal.class, mPmInternal);
+        mUserManager = injector.getUserManagerService();
+        mComponentResolver = injector.getComponentResolver();
+        mPermissionManager = injector.getPermissionManagerServiceInternal();
+        mSettings = injector.getSettings();
+        mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
+
         // CHECKSTYLE:ON IndentationCheck
         t.traceEnd();
 
@@ -2413,15 +2598,16 @@
             mSeparateProcesses = null;
         }
 
-        mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
+        mPackageDexOptimizer = new PackageDexOptimizer(mInstaller, mInstallLock, mContext,
                 "*dexopt*");
-        mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock);
-        mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
+        mDexManager =
+                new DexManager(mContext, this, mPackageDexOptimizer, mInstaller, mInstallLock);
+        mArtManagerService = new ArtManagerService(mContext, this, mInstaller, mInstallLock);
         mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
 
         mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);
 
-        getDefaultDisplayMetrics(context, mMetrics);
+        getDefaultDisplayMetrics(mInjector.getDisplayManager(), mMetrics);
 
         t.traceBegin("get system config");
         SystemConfig systemConfig = SystemConfig.getInstance();
@@ -2430,7 +2616,9 @@
 
         mProtectedPackages = new ProtectedPackages(mContext);
 
-        mApexManager = ApexManager.create(context);
+        mApexManager = ApexManager.create(mContext);
+        mAppsFilter = AppsFilter.create(mContext);
+
         // CHECKSTYLE:OFF IndentationCheck
         synchronized (mInstallLock) {
         // writer
@@ -2475,7 +2663,7 @@
             t.traceEnd();
 
             t.traceBegin("read user settings");
-            mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
+            mFirstBoot = !mSettings.readLPw(mUserManager.getUsers(false));
             t.traceEnd();
 
             // Clean up orphaned packages for which the code path doesn't exist
@@ -3082,8 +3270,9 @@
                 // the rest of the commands above) because there's precious little we
                 // can do about it. A settings error is reported, though.
                 final List<String> changedAbiCodePath =
-                        mInjector.getAbiHelper().adjustCpuAbisForSharedUser(
-                                setting.packages, null /*scannedPackage*/);
+                        applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/,
+                        mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
+                                setting.packages, null /*scannedPackage*/));
                 if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
                     for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
                         final String codePathString = changedAbiCodePath.get(i);
@@ -3128,8 +3317,8 @@
             // If this is the first boot or an update from pre-M, and it is a normal
             // boot, then we need to initialize the default preferred apps across
             // all defined users.
-            if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
-                for (UserInfo user : sUserManager.getUsers(true)) {
+            if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
+                for (UserInfo user : mUserManager.getUsers(true)) {
                     mSettings.applyDefaultPreferredAppsLPw(user.id);
                     primeDomainVerificationsLPw(user.id);
                 }
@@ -3189,7 +3378,7 @@
             // Note that we do *not* clear the application profiles. These remain valid
             // across OTAs and are used to drive profile verification (post OTA) and
             // profile compilation (without waiting to collect a fresh set of profiles).
-            if (mIsUpgrade && !onlyCore) {
+            if (mIsUpgrade && !mOnlyCore) {
                 Slog.i(TAG, "Build fingerprint changed; clearing code caches");
                 for (int i = 0; i < mSettings.mPackages.size(); i++) {
                     final PackageSetting ps = mSettings.mPackages.valueAt(i);
@@ -3206,7 +3395,7 @@
 
             // Grandfather existing (installed before Q) non-system apps to hide
             // their icons in launcher.
-            if (!onlyCore && mIsPreQUpgrade) {
+            if (!mOnlyCore && mIsPreQUpgrade) {
                 Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
                 int size = mSettings.mPackages.size();
                 for (int i = 0; i < size; i++) {
@@ -3278,7 +3467,7 @@
                 }
             }
 
-            mInstallerService = new PackageInstallerService(context, this, mApexManager);
+            mInstallerService = new PackageInstallerService(mContext, this, mApexManager);
             final Pair<ComponentName, String> instantAppResolverComponent =
                     getInstantAppResolverLPr();
             if (instantAppResolverComponent != null) {
@@ -3334,8 +3523,6 @@
         PackageParser.readConfigUseRoundIcon(mContext.getResources());
 
         mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);
-
-        t.traceEnd(); // "create package manager"
     }
 
     /**
@@ -4017,7 +4204,7 @@
     }
 
     private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         if (ps == null) {
             return null;
         }
@@ -4028,7 +4215,7 @@
         //     and 2) ephemeral apps that have explicitly interacted with it
         //   * Ephemeral apps can only see their own data and exposed installed apps
         //   * Holding a signature permission allows seeing instant apps
-        if (filterAppAccessLPr(ps, callingUid, userId)) {
+        if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
             return null;
         }
 
@@ -4095,7 +4282,7 @@
         final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+            if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                 throw new SecurityException("Package " + packageName + " was not found!");
             }
 
@@ -4120,7 +4307,7 @@
 
     @Override
     public boolean isPackageAvailable(String packageName, int userId) {
-        if (!sUserManager.exists(userId)) return false;
+        if (!mUserManager.exists(userId)) return false;
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/, "is package available");
@@ -4128,7 +4315,7 @@
             PackageParser.Package p = mPackages.get(packageName);
             if (p != null) {
                 final PackageSetting ps = (PackageSetting) p.mExtras;
-                if (filterAppAccessLPr(ps, callingUid, userId)) {
+                if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return false;
                 }
                 if (ps != null) {
@@ -4163,7 +4350,7 @@
      */
     private PackageInfo getPackageInfoInternal(String packageName, long versionCode,
             int flags, int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */, "get package info");
@@ -4185,7 +4372,7 @@
                     if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                         return null;
                     }
-                    if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
+                    if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
                         return null;
                     }
                     return generatePackageInfo(ps, flags, userId);
@@ -4203,7 +4390,7 @@
                 if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                     return null;
                 }
-                if (ps != null && filterAppAccessLPr(ps, filterCallingUid, userId)) {
+                if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
                     return null;
                 }
                 return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
@@ -4214,7 +4401,7 @@
                 if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                     return null;
                 }
-                if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
+                if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
                     return null;
                 }
                 return generatePackageInfo(ps, flags, userId);
@@ -4286,7 +4473,7 @@
      * @see #canViewInstantApps(int, int)
      */
     @GuardedBy("mLock")
-    private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid,
+    private boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
             @Nullable ComponentName component, @ComponentType int componentType, int userId) {
         // if we're in an isolated process, get the real calling UID
         if (Process.isIsolated(callingUid)) {
@@ -4337,15 +4524,18 @@
             return !mInstantAppRegistry.isInstantAccessGranted(
                     userId, UserHandle.getAppId(callingUid), ps.appId);
         }
-        return false;
+        int appId = UserHandle.getAppId(callingUid);
+        final SettingBase callingPs = mSettings.getSettingLPr(appId);
+        return mAppsFilter.shouldFilterApplication(callingUid, callingPs, ps, userId);
     }
 
     /**
-     * @see #filterAppAccessLPr(PackageSetting, int, ComponentName, int, int)
+     * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
      */
     @GuardedBy("mLock")
-    private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid, int userId) {
-        return filterAppAccessLPr(ps, callingUid, null, TYPE_UNKNOWN, userId);
+    private boolean shouldFilterApplicationLocked(
+            @Nullable PackageSetting ps, int callingUid, int userId) {
+        return shouldFilterApplicationLocked(ps, callingUid, null, TYPE_UNKNOWN, userId);
     }
 
     @GuardedBy("mLock")
@@ -4461,7 +4651,7 @@
 
     @Override
     public int getPackageUid(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return -1;
+        if (!mUserManager.exists(userId)) return -1;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -4472,7 +4662,7 @@
             final PackageParser.Package p = mPackages.get(packageName);
             if (p != null && p.isMatch(flags)) {
                 PackageSetting ps = (PackageSetting) p.mExtras;
-                if (filterAppAccessLPr(ps, callingUid, userId)) {
+                if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return -1;
                 }
                 return UserHandle.getUid(userId, p.applicationInfo.uid);
@@ -4480,7 +4670,7 @@
             if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null && ps.isMatch(flags)
-                        && !filterAppAccessLPr(ps, callingUid, userId)) {
+                        && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return UserHandle.getUid(userId, ps.appId);
                 }
             }
@@ -4491,7 +4681,7 @@
 
     @Override
     public int[] getPackageGids(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -4502,7 +4692,7 @@
             final PackageParser.Package p = mPackages.get(packageName);
             if (p != null && p.isMatch(flags)) {
                 PackageSetting ps = (PackageSetting) p.mExtras;
-                if (filterAppAccessLPr(ps, callingUid, userId)) {
+                if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return null;
                 }
                 // TODO: Shouldn't this be checking for package installed state for userId and
@@ -4512,7 +4702,7 @@
             if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null && ps.isMatch(flags)
-                        && !filterAppAccessLPr(ps, callingUid, userId)) {
+                        && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return ps.getPermissionsState().computeGids(userId);
                 }
             }
@@ -4535,13 +4725,13 @@
     @GuardedBy("mLock")
     private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                 return null;
             }
-            if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
+            if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
                 return null;
             }
             if (ps.pkg == null) {
@@ -4574,7 +4764,7 @@
      */
     private ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForApplication(flags, userId, packageName);
 
         if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
@@ -4599,7 +4789,7 @@
                 if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                     return null;
                 }
-                if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
+                if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
                     return null;
                 }
                 // Note: isEnabledLP() does not apply here - always return info
@@ -4688,7 +4878,7 @@
      * until the requested bytes are available.
      */
     public void freeStorage(String volumeUuid, long bytes, int storageFlags) throws IOException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final File file = storage.findPathForUuid(volumeUuid);
         if (file.getUsableSpace() >= bytes) return;
 
@@ -4771,14 +4961,14 @@
 
     private boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
             throws IOException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
 
         List<VersionedPackage> packagesToDelete = null;
         final long now = System.currentTimeMillis();
 
         synchronized (mLock) {
-            final int[] allUsers = sUserManager.getUserIds();
+            final int[] allUsers = mUserManager.getUserIds();
             final int libCount = mSharedLibraries.size();
             for (int i = 0; i < libCount; i++) {
                 final LongSparseArray<SharedLibraryInfo> versionedLib
@@ -4850,7 +5040,7 @@
             // give them what they want
         } else {
             // Caller expressed no opinion, so match based on user state
-            if (getUserManagerInternal().isUserUnlockingOrUnlocked(userId)) {
+            if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
                 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
             } else {
                 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -4859,43 +5049,6 @@
         return flags;
     }
 
-    private UserManagerInternal getUserManagerInternal() {
-        if (mUserManagerInternal == null) {
-            mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
-        }
-        return mUserManagerInternal;
-    }
-
-    private ActivityManagerInternal getActivityManagerInternal() {
-        if (mActivityManagerInternal == null) {
-            mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
-        }
-        return mActivityManagerInternal;
-    }
-
-    private ActivityTaskManagerInternal getActivityTaskManagerInternal() {
-        if (mActivityTaskManagerInternal == null) {
-            mActivityTaskManagerInternal =
-                    LocalServices.getService(ActivityTaskManagerInternal.class);
-        }
-        return mActivityTaskManagerInternal;
-    }
-
-    private DeviceIdleController.LocalService getDeviceIdleController() {
-        if (mDeviceIdleController == null) {
-            mDeviceIdleController =
-                    LocalServices.getService(DeviceIdleController.LocalService.class);
-        }
-        return mDeviceIdleController;
-    }
-
-    private StorageManagerInternal getStorageManagerInternal() {
-        if (mStorageManagerInternal == null) {
-            mStorageManagerInternal = LocalServices.getService(StorageManagerInternal.class);
-        }
-        return mStorageManagerInternal;
-    }
-
     /**
      * Update given flags when being used to request {@link PackageInfo}.
      */
@@ -4910,7 +5063,7 @@
                     "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
                     + Debug.getCallers(5));
         } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser
-                && sUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
+                && mUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
             // If the caller wants all packages and has a restricted profile associated with it,
             // then match all users. This is to make sure that launchers that need to access work
             // profile apps don't start breaking. TODO: Remove this hack when launchers stop using
@@ -5007,7 +5160,7 @@
      */
     private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
 
         if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
@@ -5022,7 +5175,8 @@
             if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
-                if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
+                if (shouldFilterApplicationLocked(
+                        ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
                     return null;
                 }
                 return PackageParser.generateActivityInfo(
@@ -5037,7 +5191,7 @@
     }
 
     private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
-        if (!getActivityTaskManagerInternal().isCallerRecents(callingUid)) {
+        if (!mInjector.getActivityTaskManagerInternal().isCallerRecents(callingUid)) {
             return false;
         }
         final long token = Binder.clearCallingIdentity();
@@ -5046,7 +5200,7 @@
             if (ActivityManager.getCurrentUser() != callingUserId) {
                 return false;
             }
-            return sUserManager.isSameProfileGroup(callingUserId, targetUserId);
+            return mUserManager.isSameProfileGroup(callingUserId, targetUserId);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -5070,7 +5224,8 @@
             if (ps == null) {
                 return false;
             }
-            if (filterAppAccessLPr(ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
+            if (shouldFilterApplicationLocked(
+                    ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
                 return false;
             }
             for (int i=0; i<a.intents.size(); i++) {
@@ -5085,7 +5240,7 @@
 
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -5097,7 +5252,8 @@
             if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
-                if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) {
+                if (shouldFilterApplicationLocked(
+                        ps, callingUid, component, TYPE_RECEIVER, userId)) {
                     return null;
                 }
                 return PackageParser.generateActivityInfo(
@@ -5110,7 +5266,7 @@
     @Override
     public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
             int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return null;
@@ -5192,7 +5348,7 @@
 
         Preconditions.checkNotNull(packageName, "packageName cannot be null");
         Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return null;
         }
 
@@ -5299,7 +5455,7 @@
 
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -5311,7 +5467,8 @@
             if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
-                if (filterAppAccessLPr(ps, callingUid, component, TYPE_SERVICE, userId)) {
+                if (shouldFilterApplicationLocked(
+                        ps, callingUid, component, TYPE_SERVICE, userId)) {
                     return null;
                 }
                 return PackageParser.generateServiceInfo(
@@ -5323,7 +5480,7 @@
 
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -5335,7 +5492,8 @@
             if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
-                if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+                if (shouldFilterApplicationLocked(
+                        ps, callingUid, component, TYPE_PROVIDER, userId)) {
                     return null;
                 }
                 return PackageParser.generateProviderInfo(
@@ -5607,8 +5765,8 @@
             final int callingUserId = UserHandle.getUserId(callingUid);
             final PackageSetting ps1 = (PackageSetting) p1.mExtras;
             final PackageSetting ps2 = (PackageSetting) p2.mExtras;
-            if (filterAppAccessLPr(ps1, callingUid, callingUserId)
-                    || filterAppAccessLPr(ps2, callingUid, callingUserId)) {
+            if (shouldFilterApplicationLocked(ps1, callingUid, callingUserId)
+                    || shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) {
                 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
             }
             return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures);
@@ -5636,7 +5794,7 @@
                     s1 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
                 } else if (obj instanceof PackageSetting) {
                     final PackageSetting ps = (PackageSetting) obj;
-                    if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+                    if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                         return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
                     }
                     s1 = ps.signatures.mSigningDetails.signatures;
@@ -5655,7 +5813,7 @@
                     s2 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
                 } else if (obj instanceof PackageSetting) {
                     final PackageSetting ps = (PackageSetting) obj;
-                    if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+                    if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                         return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
                     }
                     s2 = ps.signatures.mSigningDetails.signatures;
@@ -5681,7 +5839,7 @@
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
             final PackageSetting ps = (PackageSetting) p.mExtras;
-            if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+            if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 return false;
             }
             switch (type) {
@@ -5715,7 +5873,7 @@
                     signingDetails = ((SharedUserSetting)obj).signatures.mSigningDetails;
                 } else if (obj instanceof PackageSetting) {
                     final PackageSetting ps = (PackageSetting) obj;
-                    if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+                    if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                         return false;
                     }
                     signingDetails = ps.signatures.mSigningDetails;
@@ -5832,7 +5990,8 @@
                 return res;
             } else if (obj instanceof PackageSetting) {
                 final PackageSetting ps = (PackageSetting) obj;
-                if (ps.getInstalled(userId) && !filterAppAccessLPr(ps, callingUid, userId)) {
+                if (ps.getInstalled(userId)
+                        && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return new String[]{ps.name};
                 }
             }
@@ -5854,7 +6013,8 @@
                 return sus.name + ":" + sus.userId;
             } else if (obj instanceof PackageSetting) {
                 final PackageSetting ps = (PackageSetting) obj;
-                if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+                if (shouldFilterApplicationLocked(
+                        ps, callingUid, UserHandle.getUserId(callingUid))) {
                     return null;
                 }
                 return ps.name;
@@ -5882,7 +6042,8 @@
                     names[i] = "shared:" + sus.name;
                 } else if (obj instanceof PackageSetting) {
                     final PackageSetting ps = (PackageSetting) obj;
-                    if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+                    if (shouldFilterApplicationLocked(
+                            ps, callingUid, UserHandle.getUserId(callingUid))) {
                         names[i] = null;
                     } else {
                         names[i] = ps.name;
@@ -5932,7 +6093,8 @@
                 return sus.pkgFlags;
             } else if (obj instanceof PackageSetting) {
                 final PackageSetting ps = (PackageSetting) obj;
-                if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+                if (shouldFilterApplicationLocked(
+                        ps, callingUid, UserHandle.getUserId(callingUid))) {
                     return 0;
                 }
                 return ps.pkgFlags;
@@ -5955,7 +6117,8 @@
                 return sus.pkgPrivateFlags;
             } else if (obj instanceof PackageSetting) {
                 final PackageSetting ps = (PackageSetting) obj;
-                if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+                if (shouldFilterApplicationLocked(
+                        ps, callingUid, UserHandle.getUserId(callingUid))) {
                     return 0;
                 }
                 return ps.pkgPrivateFlags;
@@ -6017,7 +6180,7 @@
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
 
-            if (!sUserManager.exists(userId)) return null;
+            if (!mUserManager.exists(userId)) return null;
             final int callingUid = Binder.getCallingUid();
             flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
             mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -6042,7 +6205,7 @@
             throw new SecurityException(
                     "findPersistentPreferredActivity can only be run by the system");
         }
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return null;
         }
         final int callingUid = Binder.getCallingUid();
@@ -6355,7 +6518,7 @@
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
                     + " is holding mPackages", new Throwable());
         }
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         // Do NOT hold the packages lock; this calls up into the settings provider which
         // could cause a deadlock.
@@ -6584,7 +6747,7 @@
     private UserInfo getProfileParent(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return sUserManager.getProfileParent(userId);
+            return mUserManager.getProfileParent(userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6643,7 +6806,7 @@
     private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, int filterCallingUid, int userId,
             boolean resolveForStart, boolean allowDynamicSplits) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */,
@@ -6917,7 +7080,7 @@
 
     private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
             String resolvedType, int flags, int sourceUserId, int parentUserId) {
-        if (!sUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
+        if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
                 sourceUserId)) {
             return null;
         }
@@ -6978,7 +7141,7 @@
     private boolean isUserEnabled(int userId) {
         long callingId = Binder.clearCallingIdentity();
         try {
-            UserInfo userInfo = sUserManager.getUserInfo(userId);
+            UserInfo userInfo = mUserManager.getUserInfo(userId);
             return userInfo != null && userInfo.isEnabled();
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -7383,7 +7546,7 @@
         long ident = Binder.clearCallingIdentity();
         boolean targetIsProfile;
         try {
-            targetIsProfile = sUserManager.getUserInfo(targetUserId).isManagedProfile();
+            targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile();
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -7422,7 +7585,7 @@
     private @NonNull List<ResolveInfo> queryIntentActivityOptionsInternal(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForResolve(flags, userId, intent, callingUid,
                 false /*includeInstantApps*/);
@@ -7605,7 +7768,7 @@
 
     private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
             String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/,
@@ -7695,7 +7858,7 @@
 
     private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags,
             int userId, int callingUid) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForResolve(
                 flags, userId, intent, callingUid, false /*includeInstantApps*/);
         List<ResolveInfo> query = queryIntentServicesInternal(
@@ -7721,7 +7884,7 @@
     private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
             String resolvedType, int flags, int userId, int callingUid,
             boolean includeInstantApps) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/,
                 "query intent receivers");
@@ -7840,7 +8003,7 @@
 
     private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
             Intent intent, String resolvedType, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
         flags = updateFlagsForResolve(flags, userId, intent, callingUid,
@@ -7955,7 +8118,7 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return ParceledListSlice.emptyList();
         }
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, null);
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
         final boolean listApex = (flags & MATCH_APEX) != 0;
@@ -7974,7 +8137,7 @@
                     if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
                         continue;
                     }
-                    if (filterAppAccessLPr(ps, callingUid, userId)) {
+                    if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                         continue;
                     }
                     final PackageInfo pi = generatePackageInfo(ps, flags, userId);
@@ -7989,7 +8152,7 @@
                     if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
                         continue;
                     }
-                    if (filterAppAccessLPr(ps, callingUid, userId)) {
+                    if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                         continue;
                     }
                     final PackageInfo pi = generatePackageInfo((PackageSetting)
@@ -8055,7 +8218,7 @@
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
             String[] permissions, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, permissions);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
@@ -8097,7 +8260,7 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return Collections.emptyList();
         }
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForApplication(flags, userId, null);
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
 
@@ -8123,7 +8286,7 @@
                         if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
                             continue;
                         }
-                        if (filterAppAccessLPr(ps, callingUid, userId)) {
+                        if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                             continue;
                         }
                         ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
@@ -8149,7 +8312,7 @@
                         if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                             continue;
                         }
-                        if (filterAppAccessLPr(ps, callingUid, userId)) {
+                        if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                             continue;
                         }
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
@@ -8327,7 +8490,7 @@
     }
 
     private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, name);
         final int callingUid = Binder.getCallingUid();
         final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
@@ -8341,7 +8504,7 @@
             final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
             final ComponentName component =
                     new ComponentName(providerInfo.packageName, providerInfo.name);
-            if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+            if (shouldFilterApplicationLocked(ps, callingUid, component, TYPE_PROVIDER, userId)) {
                 return null;
             }
             return providerInfo;
@@ -8366,7 +8529,7 @@
         final int callingUid = Binder.getCallingUid();
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForComponent(flags, userId, processName);
         ArrayList<ProviderInfo> finalList = null;
         final List<ProviderInfo> matchList =
@@ -8381,7 +8544,8 @@
                 final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
                 final ComponentName component =
                         new ComponentName(providerInfo.packageName, providerInfo.name);
-                if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+                if (shouldFilterApplicationLocked(
+                        ps, callingUid, component, TYPE_PROVIDER, userId)) {
                     continue;
                 }
                 if (finalList == null) {
@@ -8407,7 +8571,8 @@
             final int callingUserId = UserHandle.getUserId(callingUid);
             final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
             if (ps == null) return null;
-            if (filterAppAccessLPr(ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
+            if (shouldFilterApplicationLocked(
+                    ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
                 return null;
             }
             final PackageParser.Instrumentation i = mInstrumentation.get(component);
@@ -8421,7 +8586,7 @@
         final int callingUid = Binder.getCallingUid();
         final int callingUserId = UserHandle.getUserId(callingUid);
         final PackageSetting ps = mSettings.mPackages.get(targetPackage);
-        if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+        if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
             return ParceledListSlice.emptyList();
         }
         return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
@@ -9740,7 +9905,7 @@
     }
 
     private int[] resolveUserIds(int userId) {
-        return (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds() : new int[] { userId };
+        return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
     }
 
     private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
@@ -10136,7 +10301,7 @@
                     if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
                         final int flags = pkg.isUpdatedSystemApp()
                                 ? PackageManager.DELETE_KEEP_DATA : 0;
-                        deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
+                        deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(),
                                 flags , null, true, null);
                     }
                     Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
@@ -10642,6 +10807,50 @@
     }
 
     /**
+     * Applies the adjusted ABI calculated by
+     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
+     * relevant packages and settings.
+     * @param sharedUserSetting The {@code SharedUserSetting} to adjust
+     * @param scannedPackage the package being scanned or null
+     * @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper}
+     * @return the list of code paths that belong to packages that had their ABIs adjusted.
+     */
+    private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
+            PackageParser.Package scannedPackage, String adjustedAbi) {
+        if (scannedPackage != null)  {
+            scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
+        }
+        List<String> changedAbiCodePath = null;
+        for (PackageSetting ps : sharedUserSetting.packages) {
+            if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+                if (ps.primaryCpuAbiString != null) {
+                    continue;
+                }
+
+                ps.primaryCpuAbiString = adjustedAbi;
+                if (ps.pkg != null && ps.pkg.applicationInfo != null
+                        && !TextUtils.equals(
+                        adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
+                    ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
+                    if (DEBUG_ABI_SELECTION) {
+                        Slog.i(TAG,
+                                "Adjusting ABI for " + ps.name + " to " + adjustedAbi
+                                        + " (scannedPackage="
+                                        + (scannedPackage != null ? scannedPackage : "null")
+                                        + ")");
+                    }
+                    if (changedAbiCodePath == null) {
+                        changedAbiCodePath = new ArrayList<>();
+                    }
+                    changedAbiCodePath.add(ps.codePathString);
+                }
+            }
+        }
+        return changedAbiCodePath;
+    }
+
+
+    /**
      * Just scans the package without any side effects.
      * <p>Not entirely true at the moment. There is still one side effect -- this
      * method potentially modifies a live {@link PackageSetting} object representing
@@ -10661,7 +10870,7 @@
             boolean isUnderFactoryTest, long currentTime)
             throws PackageManagerException {
         final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
-        final UserManagerInternal userManager = injector.getUserManager();
+        final UserManagerInternal userManager = injector.getUserManagerInternal();
         final PackageParser.Package pkg = request.pkg;
         PackageSetting pkgSetting = request.pkgSetting;
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
@@ -10767,7 +10976,7 @@
         if (!createNewPackage) {
             final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
             final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
-            setInstantAppForUser(userManager, pkgSetting, userId, instantApp, fullApp);
+            setInstantAppForUser(injector, pkgSetting, userId, instantApp, fullApp);
         }
         // TODO(patb): see if we can do away with disabled check here.
         if (disabledPkgSetting != null
@@ -10813,7 +11022,10 @@
             if (needToDeriveAbi) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
                 final boolean extractNativeLibs = !pkg.isLibrary();
-                packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
+                        packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+                derivedAbi.first.applyTo(pkg);
+                derivedAbi.second.applyTo(pkg);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
                 // Some system apps still use directory structure for native libraries
@@ -10821,8 +11033,13 @@
                 // structure. Try to detect abi based on directory structure.
                 if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
                         pkg.applicationInfo.primaryCpuAbi == null) {
-                    packageAbiHelper.setBundledAppAbisAndRoots(pkg, pkgSetting);
-                    packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                    final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
+                            pkg);
+                    abis.applyTo(pkg);
+                    abis.applyTo(pkgSetting);
+                    final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+                            packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                    nativeLibraryPaths.applyTo(pkg);
                 }
             } else {
                 // This is not a first boot or an upgrade, don't bother deriving the
@@ -10831,7 +11048,9 @@
                 pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
                 pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
 
-                packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+                        packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                nativeLibraryPaths.applyTo(pkg);
 
                 if (DEBUG_ABI_SELECTION) {
                     Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
@@ -10852,7 +11071,9 @@
             // ABIs we've determined above. For non-moves, the path will be updated based on the
             // ABIs we determined during compilation, but the path will depend on the final
             // package path (after the rename away from the stage path).
-            packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+            final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+                    packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+            nativeLibraryPaths.applyTo(pkg);
         }
 
         // This is a special case for the "system" package, where the ABI is
@@ -10906,8 +11127,9 @@
             // We also do this *before* we perform dexopt on this package, so that
             // we can avoid redundant dexopts, and also to make sure we've got the
             // code and package path correct.
-            changedAbiCodePath = packageAbiHelper.adjustCpuAbisForSharedUser(
-                            pkgSetting.sharedUser.packages, pkg);
+            changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
+                    packageAbiHelper.getAdjustedAbiForSharedUser(
+                            pkgSetting.sharedUser.packages, pkg));
         }
 
         if (isUnderFactoryTest && pkg.requestedPermissions.contains(
@@ -11678,6 +11900,7 @@
             ksms.addScannedPackageLPw(pkg);
 
             mComponentResolver.addAllComponents(pkg, chatty);
+            mAppsFilter.addPackage(pkg, mPackages);
 
             // Don't allow ephemeral applications to define new permissions groups.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
@@ -11888,7 +12111,7 @@
 
     void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
         mComponentResolver.removeAllComponents(pkg, chatty);
-
+        mAppsFilter.removePackage(pkg.packageName);
         mPermissionManager.removeAllPermissions(pkg, chatty);
 
         final int instrumentationSize = pkg.instrumentation.size();
@@ -12215,10 +12438,10 @@
      * automatically without needing an explicit launch.
      * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones.
      */
-    private void sendBootCompletedBroadcastToSystemApp(String packageName, boolean includeStopped,
-            int userId) {
+    private void sendBootCompletedBroadcastToSystemApp(
+            String packageName, boolean includeStopped, int userId) {
         // If user is not running, the app didn't miss any broadcast
-        if (!mUserManagerInternal.isUserRunning(userId)) {
+        if (!mUserManager.isUserRunning(userId)) {
             return;
         }
         final IActivityManager am = ActivityManager.getService();
@@ -12234,7 +12457,7 @@
                     android.app.AppOpsManager.OP_NONE, null, false, false, userId);
 
             // Deliver BOOT_COMPLETED only if user is unlocked
-            if (mUserManagerInternal.isUserUnlockingOrUnlocked(userId)) {
+            if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
                 Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName);
                 if (includeStopped) {
                     bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
@@ -12272,7 +12495,7 @@
                 if (pkgSetting == null) {
                     return false;
                 }
-                if (filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+                if (shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
                     return false;
                 }
                 // Do not allow "android" is being disabled
@@ -12447,7 +12670,7 @@
                 if (ps == null) {
                     return true;
                 }
-                if (filterAppAccessLPr(ps, callingUid, userId)) {
+                if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return true;
                 }
                 return ps.getHidden(userId);
@@ -12512,7 +12735,7 @@
                     // only allow the existing package to be used if it's installed as a full
                     // application for at least one user
                     boolean installAllowed = false;
-                    for (int checkUserId : sUserManager.getUserIds()) {
+                    for (int checkUserId : mUserManager.getUserIds()) {
                         installAllowed = !pkgSetting.getInstantApp(checkUserId);
                         if (installAllowed) {
                             break;
@@ -12533,8 +12756,7 @@
                     // upgrade app from instant to full; we don't allow app downgrade
                     installed = true;
                 }
-                setInstantAppForUser(
-                        getUserManagerInternal(), pkgSetting, userId, instantApp, fullApp);
+                setInstantAppForUser(mInjector, pkgSetting, userId, instantApp, fullApp);
             }
 
             if (installed) {
@@ -12582,7 +12804,7 @@
         }
     }
 
-    static void setInstantAppForUser(UserManagerInternal userManager, PackageSetting pkgSetting,
+    static void setInstantAppForUser(Injector injector, PackageSetting pkgSetting,
             int userId, boolean instantApp, boolean fullApp) {
         // no state specified; do nothing
         if (!instantApp && !fullApp) {
@@ -12595,7 +12817,7 @@
                 pkgSetting.setInstantApp(false /*instantApp*/, userId);
             }
         } else {
-            for (int currentUserId : userManager.getUserIds()) {
+            for (int currentUserId : injector.getUserManagerInternal().getUserIds()) {
                 if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
                     pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
                 } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
@@ -12606,7 +12828,7 @@
     }
 
     boolean isUserRestricted(int userId, String restrictionKey) {
-        Bundle restrictions = sUserManager.getUserRestrictions(userId);
+        Bundle restrictions = mUserManager.getUserRestrictions(userId);
         if (restrictions.getBoolean(restrictionKey, false)) {
             Log.w(TAG, "User is restricted: " + restrictionKey);
             return true;
@@ -12639,7 +12861,8 @@
             final PackageSetting pkgSetting;
             synchronized (mLock) {
                 pkgSetting = mSettings.mPackages.get(packageName);
-                if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+                if (pkgSetting == null
+                        || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
                     Slog.w(TAG, "Could not find package setting for package: " + packageName
                             + ". Skipping...");
                     unactionedPackages.add(packageName);
@@ -12731,7 +12954,8 @@
             final PackageSetting pkgSetting;
             synchronized (mLock) {
                 pkgSetting = mSettings.mPackages.get(packageName);
-                if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+                if (pkgSetting == null
+                        || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
                     Slog.w(TAG, "Could not find package setting for package: " + packageName
                             + ". Skipping suspending/un-suspending.");
                     unactionedPackages.add(packageName);
@@ -12772,7 +12996,7 @@
         }
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+            if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                 throw new IllegalArgumentException("Unknown target package: " + packageName);
             }
             final PackageUserState packageUserState = ps.readUserState(userId);
@@ -12824,7 +13048,7 @@
                 "isPackageSuspendedForUser for user " + userId);
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+            if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                 throw new IllegalArgumentException("Unknown target package: " + packageName);
             }
             return ps.getSuspended(userId);
@@ -12842,7 +13066,7 @@
      * @param affectedUser The user for which the changes are taking place.
      */
     void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
-        final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+        final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? mUserManager.getUserIds()
                 : new int[] {affectedUser};
         for (int userId : userIds) {
             unsuspendForSuspendingPackages(packageName::equals, userId);
@@ -13198,7 +13422,7 @@
      * @return default verification response code
      */
     private int getDefaultVerificationResponse(UserHandle user) {
-        if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
+        if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
             return PackageManager.VERIFICATION_REJECT;
         }
         return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
@@ -13244,7 +13468,7 @@
                         && mInstantAppInstallerActivity.packageName.equals(
                                 mRequiredVerifierPackage)) {
                     try {
-                        mContext.getSystemService(AppOpsManager.class)
+                        mInjector.getAppOpsManager()
                                 .checkPackage(installerUid, mRequiredVerifierPackage);
                         if (DEBUG_VERIFY) {
                             Slog.i(TAG, "disable verification for instant app");
@@ -13292,7 +13516,8 @@
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps == null
-                    || filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+                    || shouldFilterApplicationLocked(
+                    ps, callingUid, UserHandle.getUserId(callingUid))) {
                 return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
             }
             return mSettings.getIntentFilterVerificationStatusLPr(packageName, userId);
@@ -13307,7 +13532,8 @@
         boolean result = false;
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (filterAppAccessLPr(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+            if (shouldFilterApplicationLocked(
+                    ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
                 return false;
             }
             result = mSettings.updateIntentFilterVerificationStatusLPw(packageName, status, userId);
@@ -13327,7 +13553,7 @@
         }
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+            if (shouldFilterApplicationLocked(ps, callingUid, UserHandle.getUserId(callingUid))) {
                 return ParceledListSlice.emptyList();
             }
             return new ParceledListSlice<>(mSettings.getIntentFilterVerificationsLPr(packageName));
@@ -13350,7 +13576,7 @@
                 return ParceledListSlice.emptyList();
             }
             final PackageSetting ps = (PackageSetting) pkg.mExtras;
-            if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+            if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 return ParceledListSlice.emptyList();
             }
             final int count = pkg.activities.size();
@@ -13386,7 +13612,7 @@
         synchronized (mLock) {
             PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage);
             if (targetPackageSetting == null
-                    || filterAppAccessLPr(
+                    || shouldFilterApplicationLocked(
                             targetPackageSetting, callingUid, UserHandle.getUserId(callingUid))) {
                 throw new IllegalArgumentException("Unknown target package: " + targetPackage);
             }
@@ -13463,14 +13689,15 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             throw new SecurityException("Instant applications don't have access to this method");
         }
-        mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
+        mInjector.getAppOpsManager().checkPackage(Binder.getCallingUid(),
                 callerPackageName);
         synchronized (mLock) {
             PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps == null) {
                 throw new IllegalArgumentException("Unknown target package " + packageName);
             }
-            if (filterAppAccessLPr(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+            if (shouldFilterApplicationLocked(
+                    ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
                 throw new IllegalArgumentException("Unknown target package " + packageName);
             }
             if (!Objects.equals(callerPackageName, ps.installerPackageName)) {
@@ -13607,7 +13834,7 @@
 
             final String packageName = res.pkg.applicationInfo.packageName;
             final String seInfo = res.pkg.applicationInfo.seInfo;
-            final int[] allUsers = sUserManager.getUserIds();
+            final int[] allUsers = mUserManager.getUserIds();
             final int[] installedUsers;
 
             final PackageSetting ps;
@@ -14280,7 +14507,8 @@
                     final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                             receivers, verificationState);
 
-                    DeviceIdleController.LocalService idleController = getDeviceIdleController();
+                    DeviceIdleController.LocalService idleController =
+                            mInjector.getLocalDeviceIdleController();
                     final long idleDuration = getVerificationTimeout();
 
                     /*
@@ -14352,7 +14580,7 @@
                     synchronized (mLock) {
                         PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
                         if (ps != null) {
-                            installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
+                            installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(),
                                     true);
                         } else {
                             installedUsers = new int[0];
@@ -14872,7 +15100,7 @@
             final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
                     move.dataAppName);
             Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid);
-            final int[] userIds = sUserManager.getUserIds();
+            final int[] userIds = mUserManager.getUserIds();
             synchronized (mInstallLock) {
                 // Clean up both app data and code
                 // All package moves are frozen until finished
@@ -15153,7 +15381,7 @@
 
                 // Set install reason for users that are having the package newly installed.
                 if (userId == UserHandle.USER_ALL) {
-                    for (int currentUserId : sUserManager.getUserIds()) {
+                    for (int currentUserId : mUserManager.getUserIds()) {
                         if (!previousUserIds.contains(currentUserId)) {
                             ps.setInstallReason(installReason, currentUserId);
                         }
@@ -15786,7 +16014,7 @@
 
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps != null) {
-                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
                 ps.setUpdateAvailable(false /*updateAvailable*/);
             }
             final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
@@ -15797,7 +16025,7 @@
                 PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                 if (childPs != null) {
                     childRes.newUsers = childPs.queryInstalledUsers(
-                            sUserManager.getUserIds(), true);
+                            mUserManager.getUserIds(), true);
                 }
             }
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
@@ -15917,7 +16145,7 @@
                 try {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                     commitRequest = new CommitRequest(reconciledPackages,
-                            sUserManager.getUserIds());
+                            mUserManager.getUserIds());
                     commitPackagesLocked(commitRequest);
                     success = true;
                 } finally {
@@ -16213,7 +16441,7 @@
                     PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                     if (childPs != null) {
                         childRes.origUsers = childPs.queryInstalledUsers(
-                                sUserManager.getUserIds(), true);
+                                mUserManager.getUserIds(), true);
                     }
                     if ((mPackages.containsKey(childPkg.packageName))) {
                         childRes.removedInfo = new PackageRemovedInfo(this);
@@ -16378,7 +16606,7 @@
                     systemApp = (ps.pkg.applicationInfo.flags &
                             ApplicationInfo.FLAG_SYSTEM) != 0;
                 }
-                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
             }
 
 
@@ -16506,7 +16734,11 @@
                 String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                         args.abiOverride : pkg.cpuAbiOverride);
                 final boolean extractNativeLibs = !pkg.isLibrary();
-                mInjector.getAbiHelper().derivePackageAbi(pkg, abiOverride, extractNativeLibs);
+                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
+                        derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
+                                pkg, abiOverride, extractNativeLibs);
+                derivedAbi.first.applyTo(pkg);
+                derivedAbi.second.applyTo(pkg);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -16633,7 +16865,7 @@
                     }
 
                     // In case of rollback, remember per-user/profile install state
-                    allUsers = sUserManager.getUserIds();
+                    allUsers = mUserManager.getUserIds();
                     installedUsers = ps.queryInstalledUsers(allUsers, true);
 
 
@@ -17144,7 +17376,7 @@
             return;
         }
         final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
-        final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{userId};
+        final int[] users = deleteAllUsers ? mUserManager.getUserIds() : new int[]{userId};
         if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -17394,7 +17626,7 @@
                 // Does it contain a device admin for any user?
                 int[] users;
                 if (userId == UserHandle.USER_ALL) {
-                    users = sUserManager.getUserIds();
+                    users = mUserManager.getUserIds();
                 } else {
                     users = new int[]{userId};
                 }
@@ -17471,7 +17703,7 @@
             // allow removing a package if it provides a lib others depend on.
             pkg = mPackages.get(packageName);
 
-            allUsers = sUserManager.getUserIds();
+            allUsers = mUserManager.getUserIds();
 
             if (pkg != null && pkg.staticSharedLibName != null) {
                 SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName,
@@ -17721,7 +17953,7 @@
             outInfo.isStaticSharedLib = deletedPkg != null
                     && deletedPkg.staticSharedLibName != null;
             outInfo.populateUsers(deletedPs == null ? null
-                    : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs);
+                    : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
         }
 
         removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0);
@@ -17820,7 +18052,8 @@
         if (removedAppId != -1) {
             // A user ID was deleted here. Go through all users and remove it
             // from KeyStore.
-            removeKeystoreDataIfNeeded(UserHandle.USER_ALL, removedAppId);
+            removeKeystoreDataIfNeeded(
+                    mInjector.getUserManagerInternal(), UserHandle.USER_ALL, removedAppId);
         }
     }
 
@@ -18155,7 +18388,7 @@
     public boolean getBlockUninstallForUser(String packageName, int userId) {
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (ps == null || filterAppAccessLPr(ps, Binder.getCallingUid(), userId)) {
+            if (ps == null || shouldFilterApplicationLocked(ps, Binder.getCallingUid(), userId)) {
                 return false;
             }
             return mSettings.getBlockUninstallLPr(userId, packageName);
@@ -18327,7 +18560,7 @@
                 if (!systemApp) {
                     // Do not uninstall the APK if an app should be cached
                     boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName);
-                    if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) {
+                    if (ps.isAnyInstalled(mUserManager.getUserIds()) || keepUninstalledPackage) {
                         // Other users still have this package installed, so all
                         // we need to do is clear this user's data and save that
                         // it is uninstalled.
@@ -18441,7 +18674,7 @@
     @GuardedBy("mLock")
     private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user) {
         final int[] userIds = (user == null || user.getIdentifier() == UserHandle.USER_ALL)
-                ? sUserManager.getUserIds() : new int[] {user.getIdentifier()};
+                ? mUserManager.getUserIds() : new int[] {user.getIdentifier()};
         for (int nextUserId : userIds) {
             if (DEBUG_REMOVE) {
                 Slog.d(TAG, "Marking package:" + ps.name + " uninstalled for user:" + nextUserId);
@@ -18478,7 +18711,7 @@
 
         destroyAppProfilesLIF(pkg);
 
-        final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+        final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds()
                 : new int[] {userId};
         for (int nextUserId : userIds) {
             if (DEBUG_REMOVE) {
@@ -18489,7 +18722,7 @@
             destroyAppDataLIF(pkg, nextUserId,
                     FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
             clearDefaultBrowserIfNeededForUser(ps.name, nextUserId);
-            removeKeystoreDataIfNeeded(nextUserId, ps.appId);
+            removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);
             final SparseBooleanArray changedUsers = new SparseBooleanArray();
             clearPackagePreferredActivitiesLPw(ps.name, changedUsers, nextUserId);
             if (changedUsers.size() > 0) {
@@ -18547,7 +18780,8 @@
                 true /* requireFullPermission */, false /* checkShell */, "clear application data");
 
         final PackageSetting ps = mSettings.getPackageLPr(packageName);
-        final boolean filterApp = (ps != null && filterAppAccessLPr(ps, callingUid, userId));
+        final boolean filterApp =
+                (ps != null && shouldFilterApplicationLocked(ps, callingUid, userId));
         if (!filterApp && mProtectedPackages.isPackageDataProtected(userId, packageName)) {
             throw new SecurityException("Cannot clear data for a protected package: "
                     + packageName);
@@ -18621,9 +18855,9 @@
                 FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
 
         final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
-        removeKeystoreDataIfNeeded(userId, appId);
+        removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId);
 
-        UserManagerInternal umInternal = getUserManagerInternal();
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
         final int flags;
         if (umInternal.isUserUnlockingOrUnlocked(userId)) {
             flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -18638,14 +18872,14 @@
     }
 
     private void resetNetworkPolicies(int userId) {
-        LocalServices.getService(NetworkPolicyManagerInternal.class).resetUserState(userId);
+        mInjector.getNetworkPolicyManagerInternal().resetUserState(userId);
     }
 
     /**
      * Remove entries from the keystore daemon. Will only remove it if the
      * {@code appId} is valid.
      */
-    private static void removeKeystoreDataIfNeeded(int userId, int appId) {
+    private static void removeKeystoreDataIfNeeded(UserManagerInternal um, int userId, int appId) {
         if (appId < 0) {
             return;
         }
@@ -18653,7 +18887,7 @@
         final KeyStore keyStore = KeyStore.getInstance();
         if (keyStore != null) {
             if (userId == UserHandle.USER_ALL) {
-                for (final int individual : sUserManager.getUserIds()) {
+                for (final int individual : um.getUserIds()) {
                     keyStore.clearUid(UserHandle.getUid(individual, appId));
                 }
             } else {
@@ -18987,7 +19221,8 @@
             }
             final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps != null
-                    && filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+                    && shouldFilterApplicationLocked(
+                            ps, callingUid, UserHandle.getUserId(callingUid))) {
                 return;
             }
         }
@@ -19053,8 +19288,8 @@
     void clearIntentFilterVerificationsLPw(String packageName, int userId) {
         if (userId == UserHandle.USER_ALL) {
             if (mSettings.removeIntentFilterVerificationLPw(packageName,
-                    sUserManager.getUserIds())) {
-                for (int oneUserId : sUserManager.getUserIds()) {
+                    mUserManager.getUserIds())) {
+                for (int oneUserId : mUserManager.getUserIds()) {
                     scheduleWritePackageRestrictionsLocked(oneUserId);
                 }
             }
@@ -19067,7 +19302,7 @@
 
     /** Clears state for all users, and touches intent filter verification policy */
     void clearDefaultBrowserIfNeeded(String packageName) {
-        for (int oneUserId : sUserManager.getUserIds()) {
+        for (int oneUserId : mUserManager.getUserIds()) {
             clearDefaultBrowserIfNeededForUser(packageName, oneUserId);
         }
     }
@@ -19434,7 +19669,7 @@
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         int callingUid = Binder.getCallingUid();
         enforceOwnerRights(ownerPackage, callingUid);
-        PackageManagerServiceUtils.enforceShellRestriction(
+        PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
                 UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
         if (intentFilter.countActions() == 0) {
             Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
@@ -19466,7 +19701,7 @@
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         final int callingUid = Binder.getCallingUid();
         enforceOwnerRights(ownerPackage, callingUid);
-        PackageManagerServiceUtils.enforceShellRestriction(
+        PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
                 UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
         synchronized (mLock) {
             CrossProfileIntentResolver resolver =
@@ -19815,7 +20050,7 @@
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         if (callingPackage == null) {
             callingPackage = Integer.toString(Binder.getCallingUid());
         }
@@ -19836,7 +20071,7 @@
     @Override
     public void setComponentEnabledSetting(ComponentName componentName,
             int newState, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         setEnabledSetting(componentName.getPackageName(),
                 componentName.getClassName(), newState, flags, userId, null);
     }
@@ -19896,7 +20131,7 @@
         if (!UserHandle.isSameApp(callingUid, pkgSetting.appId)) {
             // Don't allow apps that don't have permission to modify other apps
             if (!allowedByPermission
-                    || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+                    || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
                 throw new SecurityException(
                         "Attempt to change component state; "
                         + "pid=" + Binder.getCallingPid()
@@ -20063,7 +20298,7 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return;
         }
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return;
         }
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
@@ -20104,7 +20339,7 @@
 
     @Override
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         final int callingUid = Binder.getCallingUid();
         if (getInstantAppPackageName(callingUid) != null) {
             return;
@@ -20117,7 +20352,7 @@
         // writer
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (!filterAppAccessLPr(ps, callingUid, userId)
+            if (!shouldFilterApplicationLocked(ps, callingUid, userId)
                     && mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
                             allowedByPermission, callingUid, userId)) {
                 scheduleWritePackageRestrictionsLocked(userId);
@@ -20130,7 +20365,8 @@
         final int callingUid = Binder.getCallingUid();
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+            if (shouldFilterApplicationLocked(
+                    ps, callingUid, UserHandle.getUserId(callingUid))) {
                 return null;
             }
             // InstallerPackageName for Apex is not stored in PackageManager
@@ -20153,13 +20389,14 @@
 
     @Override
     public int getApplicationEnabledSetting(String packageName, int userId) {
-        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
+        if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get enabled");
         // reader
         synchronized (mLock) {
-            if (filterAppAccessLPr(mSettings.getPackageLPr(packageName), callingUid, userId)) {
+            if (shouldFilterApplicationLocked(
+                    mSettings.getPackageLPr(packageName), callingUid, userId)) {
                 return COMPONENT_ENABLED_STATE_DISABLED;
             }
             return mSettings.getApplicationEnabledSettingLPr(packageName, userId);
@@ -20169,12 +20406,13 @@
     @Override
     public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
         if (component == null) return COMPONENT_ENABLED_STATE_DEFAULT;
-        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
+        if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled");
         synchronized (mLock) {
-            if (filterAppAccessLPr(mSettings.getPackageLPr(component.getPackageName()), callingUid,
+            if (shouldFilterApplicationLocked(
+                    mSettings.getPackageLPr(component.getPackageName()), callingUid,
                     component, TYPE_UNKNOWN, userId)) {
                 return COMPONENT_ENABLED_STATE_DISABLED;
             }
@@ -20266,24 +20504,34 @@
             }
         }
 
-        sUserManager.systemReady();
+        mUserManager.systemReady();
 
         // Now that we've scanned all packages, and granted any default
         // permissions, ensure permissions are updated. Beware of dragons if you
         // try optimizing this.
         synchronized (mLock) {
             mPermissionManager.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, false);
+
+            final PermissionPolicyInternal permissionPolicyInternal =
+                    mInjector.getPermissionPolicyInternal();
+            permissionPolicyInternal.setOnInitializedCallback(userId -> {
+                // The SDK updated case is already handled when we run during the ctor.
+                synchronized (mPackages) {
+                    mPermissionManager.updateAllPermissions(
+                            StorageManager.UUID_PRIVATE_INTERNAL, false);
+                }
+            });
         }
 
         // Watch for external volumes that come and go over time
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         storage.registerListener(mStorageListener);
 
         mInstallerService.systemReady();
         mApexManager.systemReady();
         mPackageDexOptimizer.systemReady();
 
-        getStorageManagerInternal().addExternalStoragePolicy(
+        mInjector.getStorageManagerInternal().addExternalStoragePolicy(
                 new StorageManagerInternal.ExternalStorageMountPolicy() {
             @Override
             public int getMountMode(int uid, String packageName) {
@@ -20306,7 +20554,7 @@
         });
 
         // Now that we're mostly running, clean up stale users and apps
-        sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
+        mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
         reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
 
         mPermissionManager.systemReady();
@@ -20784,7 +21032,7 @@
                             pw.println(prefix + "No app verification established.");
                             pw.println();
                         }
-                        for (int userId : sUserManager.getUserIds()) {
+                        for (int userId : mUserManager.getUserIds()) {
                             pw.println("App linkages for user " + userId + ":");
                             pw.println();
                             count = 0;
@@ -20949,7 +21197,7 @@
         }
         for (String packageName : apkList) {
             setSystemAppHiddenUntilInstalled(packageName, true);
-            for (UserInfo user : sUserManager.getUsers(false)) {
+            for (UserInfo user : mUserManager.getUsers(false)) {
                 setSystemAppInstallState(packageName, false, user.id);
             }
         }
@@ -21235,10 +21483,9 @@
         }
 
         // Reconcile app data for all started/unlocked users
-        final StorageManager sm = mContext.getSystemService(StorageManager.class);
-        final UserManager um = mContext.getSystemService(UserManager.class);
-        UserManagerInternal umInternal = getUserManagerInternal();
-        for (UserInfo user : um.getUsers()) {
+        final StorageManager sm = mInjector.getStorageManager();
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
+        for (UserInfo user : mUserManager.getUsers(false /* includeDying */)) {
             final int flags;
             if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -21428,7 +21675,7 @@
      * correct for all installed apps on all mounted volumes.
      */
     void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
             final String volumeUuid = vol.getFsUuid();
             synchronized (mInstallLock) {
@@ -21557,9 +21804,8 @@
             mSettings.writeKernelMappingLPr(ps);
         }
 
-        final UserManager um = mContext.getSystemService(UserManager.class);
-        UserManagerInternal umInternal = getUserManagerInternal();
-        for (UserInfo user : um.getUsers()) {
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
+        for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) {
             final int flags;
             if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -21890,7 +22136,7 @@
     private void movePackageInternal(final String packageName, final String volumeUuid,
             final int moveId, final int callingUid, UserHandle user)
                     throws PackageManagerException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final PackageManager pm = mContext.getPackageManager();
 
         final String currentVolumeUuid;
@@ -21911,7 +22157,7 @@
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (pkg == null
                     || ps == null
-                    || filterAppAccessLPr(ps, callingUid, user.getIdentifier())) {
+                    || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
                 throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
             }
             if (pkg.applicationInfo.isSystemApp()) {
@@ -21959,7 +22205,7 @@
             label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
             targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
             freezer = freezePackage(packageName, "movePackageInternal");
-            installedUserIds = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+            installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
         }
 
         final Bundle extras = new Bundle();
@@ -22126,7 +22372,7 @@
             return;
         }
 
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
         int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
 
@@ -22164,7 +22410,7 @@
             }
         };
 
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         storage.setPrimaryStorageUuid(volumeUuid, callback);
         return realMoveId;
     }
@@ -22310,7 +22556,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             final DeviceStorageMonitorInternal
-                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+                    dsm = mInjector.getDeviceStorageMonitorInternal();
             if (dsm != null) {
                 return dsm.isMemoryLow();
             } else {
@@ -22340,7 +22586,7 @@
             final UserInfo userInfo;
             final long token = Binder.clearCallingIdentity();
             try {
-                userInfo = sUserManager.getUserInfo(userId);
+                userInfo = mUserManager.getUserInfo(userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -22368,7 +22614,8 @@
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
             final PackageSetting ps = (PackageSetting) pkg.mExtras;
-            if (filterAppAccessLPr(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+            if (shouldFilterApplicationLocked(
+                    ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
                 Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
@@ -22391,7 +22638,7 @@
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
             final PackageSetting ps = (PackageSetting) pkg.mExtras;
-            if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+            if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 // filter and pretend the package doesn't exist
                 Slog.w(TAG, "KeySet requested for filtered package: " + packageName
                         + ", uid:" + callingUid);
@@ -22418,7 +22665,7 @@
         synchronized (mLock) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null
-                    || filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid,
+                    || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
                             UserHandle.getUserId(callingUid))) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -22444,7 +22691,7 @@
         synchronized (mLock) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null
-                    || filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid,
+                    || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
                             UserHandle.getUserId(callingUid))) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -22464,7 +22711,7 @@
         if (ps == null) {
             return;
         }
-        if (!ps.isAnyInstalled(sUserManager.getUserIds())) {
+        if (!ps.isAnyInstalled(mUserManager.getUserIds())) {
             // TODO Implement atomic delete if package is unused
             // It is currently possible that the package will be deleted even if it is installed
             // after this method returns.
@@ -22768,8 +23015,8 @@
         @Override
         public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) {
             synchronized (mLock) {
-                return PackageManagerService.this
-                        .filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid, userId);
+                return PackageManagerService.this.shouldFilterApplicationLocked(
+                        (PackageSetting) pkg.mExtras, callingUid, userId);
             }
         }
 
@@ -22781,7 +23028,8 @@
                     return false;
                 }
                 return PackageManagerService.this
-                        .filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid, userId);
+                        .shouldFilterApplicationLocked(
+                                (PackageSetting) pkg.mExtras, callingUid, userId);
             }
         }
 
@@ -23264,7 +23512,7 @@
         public boolean canAccessComponent(int callingUid, ComponentName component, int userId) {
             synchronized (mLock) {
                 final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
-                return ps != null && !PackageManagerService.this.filterAppAccessLPr(
+                return ps != null && !PackageManagerService.this.shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_UNKNOWN, userId);
             }
         }
@@ -23699,7 +23947,7 @@
                 "get install reason");
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (filterAppAccessLPr(ps, callingUid, userId)) {
+            if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                 return PackageManager.INSTALL_REASON_UNKNOWN;
             }
             if (ps != null) {
@@ -23746,8 +23994,8 @@
                 return false;
             }
         }
-        if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)
-                  || sUserManager.hasUserRestriction(
+        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)
+                  || mUserManager.hasUserRestriction(
                         UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userId)) {
             return false;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 4c7db9a..ef47410 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -47,6 +47,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.service.pm.PackageServiceDumpProto;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -375,10 +376,12 @@
         }
     }
 
-    public static void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
+    /** Enforces that if the caller is shell, it does not have the provided user restriction. */
+    public static void enforceShellRestriction(
+            UserManagerInternal userManager, String restriction, int callingUid, int userHandle) {
         if (callingUid == Process.SHELL_UID) {
             if (userHandle >= 0
-                    && PackageManagerService.sUserManager.hasUserRestriction(
+                    && userManager.hasUserRestriction(
                             restriction, userHandle)) {
                 throw new SecurityException("Shell does not have permission to access user "
                         + userHandle);
diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java
index a374e14..231168e 100644
--- a/services/core/java/com/android/server/pm/ProtectedPackages.java
+++ b/services/core/java/com/android/server/pm/ProtectedPackages.java
@@ -92,6 +92,9 @@
         if (mDeviceOwnerUserId == userId) {
             return mDeviceOwnerPackage;
         }
+        if (mProfileOwnerPackages == null) {
+            return null;
+        }
         return mProfileOwnerPackages.get(userId);
     }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f4ba449..a707aa8 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -576,6 +576,14 @@
                 null, mHandler);
     }
 
+    /**
+     * This method retrieves the  {@link UserManagerInternal} only for the purpose of
+     * PackageManagerService construction.
+     */
+    UserManagerInternal getInternalForInjectorOnly() {
+        return mLocalService;
+    }
+
     void cleanupPartialUsers() {
         // Prune out any partially created, partially removed and ephemeral users.
         ArrayList<UserInfo> partials = new ArrayList<>();
@@ -1549,11 +1557,7 @@
     /** @return a specific user restriction that's in effect currently. */
     @Override
     public boolean hasUserRestriction(String restrictionKey, int userId) {
-        if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
-            return false;
-        }
-        Bundle restrictions = getEffectiveUserRestrictions(userId);
-        return restrictions != null && restrictions.getBoolean(restrictionKey);
+        return mLocalService.hasUserRestriction(restrictionKey, userId);
     }
 
     /** @return if any user has the given restriction. */
@@ -4120,6 +4124,15 @@
             return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId,
                     value, callingUid);
         }
+
+        @Override
+        public boolean hasUserRestriction(String restrictionKey, int userId) {
+            if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
+                return false;
+            }
+            Bundle restrictions = getEffectiveUserRestrictions(userId);
+            return restrictions != null && restrictions.getBoolean(restrictionKey);
+        }
     }
 
     /* Remove all the users except of the system one. */
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 fe0b3a3..3e655ed 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1170,6 +1170,11 @@
                 final int flags = mContext.getPackageManager().getPermissionFlags(
                         permission, pkg.packageName, user);
 
+                // If we are trying to grant as system fixed and already system fixed
+                // then the system can change the system fixed grant state.
+                final boolean changingGrantForSystemFixed = systemFixed
+                        && (flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0;
+
                 // Certain flags imply that the permission's current state by the system or
                 // device/profile owner or the user. In these cases we do not want to clobber the
                 // current state.
@@ -1177,7 +1182,8 @@
                 // Unless the caller wants to override user choices. The override is
                 // to make sure we can grant the needed permission to the default
                 // sms and phone apps after the user chooses this in the UI.
-                if (!isFixedOrUserSet(flags) || ignoreSystemPackage) {
+                if (!isFixedOrUserSet(flags) || ignoreSystemPackage
+                        || changingGrantForSystemFixed) {
                     // Never clobber policy fixed permissions.
                     // We must allow the grant of a system-fixed permission because
                     // system-fixed is sticky, but the permission itself may be revoked.
@@ -1196,6 +1202,14 @@
                                 PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
                     }
 
+                    // If the system tries to change a system fixed permission from one fixed
+                    // state to another we need to drop the fixed flag to allow the grant.
+                    if (changingGrantForSystemFixed) {
+                        mContext.getPackageManager().updatePermissionFlags(permission,
+                                pkg.packageName, flags,
+                                flags & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, user);
+                    }
+
                     if (pm.checkPermission(permission, pkg.packageName)
                             != PackageManager.PERMISSION_GRANTED) {
                         mContext.getPackageManager()
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 674e892..e2644ff 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -125,6 +125,7 @@
 import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionsState.PermissionState;
+import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.policy.SoftRestrictedPermissionPolicy;
 
 import libcore.util.EmptyArray;
@@ -227,6 +228,9 @@
     @GuardedBy("mLock")
     private boolean mSystemReady;
 
+    @GuardedBy("mLock")
+    private PermissionPolicyInternal mPermissionPolicyInternal;
+
     /**
      * For each foreground/background permission the mapping:
      * Background permission -> foreground permissions
@@ -1193,7 +1197,8 @@
 
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
+            Log.e(TAG, "Unknown package: " + packageName);
+            return;
         }
         final BasePermission bp;
         synchronized (mLock) {
@@ -1353,7 +1358,8 @@
 
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
+            Log.e(TAG, "Unknown package: " + packageName);
+            return;
         }
         if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -2443,6 +2449,13 @@
                             boolean softRestricted = bp.isSoftRestricted();
 
                             for (int userId : currentUserIds) {
+                                // If permission policy is not ready we don't deal with restricted
+                                // permissions as the policy may whitelist some permissions. Once
+                                // the policy is initialized we would re-evaluate permissions.
+                                final boolean permissionPolicyInitialized =
+                                        mPermissionPolicyInternal != null
+                                                && mPermissionPolicyInternal.isInitialized(userId);
+
                                 PermissionState permState = origPermissions
                                         .getRuntimePermissionState(perm, userId);
                                 int flags = permState != null ? permState.getFlags() : 0;
@@ -2457,7 +2470,7 @@
 
                                 if (appSupportsRuntimePermissions) {
                                     // If hard restricted we don't allow holding it
-                                    if (hardRestricted) {
+                                    if (permissionPolicyInitialized && hardRestricted) {
                                         if (!restrictionExempt) {
                                             if (permState != null && permState.isGranted()
                                                     && permissionsState.revokeRuntimePermission(
@@ -2470,7 +2483,7 @@
                                             }
                                         }
                                     // If soft restricted we allow holding in a restricted form
-                                    } else if (softRestricted) {
+                                    } else if (permissionPolicyInitialized && softRestricted) {
                                         // Regardless if granted set the restriction flag as it
                                         // may affect app treatment based on this permission.
                                         if (!restrictionExempt && !restrictionApplied) {
@@ -2489,7 +2502,8 @@
                                         flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
                                         wasChanged = true;
                                     // Hard restricted permissions cannot be held.
-                                    } else if (!hardRestricted || restrictionExempt) {
+                                    } else if (!permissionPolicyInitialized
+                                            || (!hardRestricted || restrictionExempt)) {
                                         if (permState != null && permState.isGranted()) {
                                             if (permissionsState.grantRuntimePermission(bp, userId)
                                                     == PERMISSION_OPERATION_FAILURE) {
@@ -2518,33 +2532,28 @@
 
                                     // If legacy app always grant the permission but if restricted
                                     // and not exempt take a note a restriction should be applied.
-                                    if ((hardRestricted || softRestricted)
-                                            && !restrictionExempt && !restrictionApplied) {
+                                    if (permissionPolicyInitialized
+                                            && (hardRestricted || softRestricted)
+                                                    && !restrictionExempt && !restrictionApplied) {
                                         flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
                                         wasChanged = true;
                                     }
                                 }
 
                                 // If unrestricted or restriction exempt, don't apply restriction.
-                                if (!(hardRestricted || softRestricted) || restrictionExempt)  {
-                                    if (restrictionApplied) {
-                                        flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
-                                        // Dropping restriction on a legacy app requires a review.
-                                        if (!appSupportsRuntimePermissions) {
-                                            flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+                                if (permissionPolicyInitialized) {
+                                    if (!(hardRestricted || softRestricted) || restrictionExempt) {
+                                        if (restrictionApplied) {
+                                            flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
+                                            // Dropping restriction on a legacy app implies a review
+                                            if (!appSupportsRuntimePermissions) {
+                                                flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+                                            }
+                                            wasChanged = true;
                                         }
-                                        wasChanged = true;
                                     }
                                 }
 
-                                if (hardRestricted && !restrictionExempt
-                                        && (flags & FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
-                                    // Applying a hard restriction implies revoking it. This might
-                                    // lead to a system-fixed, revoked permission.
-                                    flags &= ~FLAG_PERMISSION_SYSTEM_FIXED;
-                                    wasChanged = true;
-                                }
-
                                 if (wasChanged) {
                                     updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
                                 }
@@ -2579,6 +2588,13 @@
                             boolean softRestricted = bp.isSoftRestricted();
 
                             for (int userId : currentUserIds) {
+                                // If permission policy is not ready we don't deal with restricted
+                                // permissions as the policy may whitelist some permissions. Once
+                                // the policy is initialized we would re-evaluate permissions.
+                                final boolean permissionPolicyInitialized =
+                                        mPermissionPolicyInternal != null
+                                                && mPermissionPolicyInternal.isInitialized(userId);
+
                                 boolean wasChanged = false;
 
                                 boolean restrictionExempt =
@@ -2589,7 +2605,7 @@
 
                                 if (appSupportsRuntimePermissions) {
                                     // If hard restricted we don't allow holding it
-                                    if (hardRestricted) {
+                                    if (permissionPolicyInitialized && hardRestricted) {
                                         if (!restrictionExempt) {
                                             if (permState != null && permState.isGranted()
                                                     && permissionsState.revokeRuntimePermission(
@@ -2602,7 +2618,7 @@
                                             }
                                         }
                                     // If soft restricted we allow holding in a restricted form
-                                    } else if (softRestricted) {
+                                    } else if (permissionPolicyInitialized && softRestricted) {
                                         // Regardless if granted set the  restriction flag as it
                                         // may affect app treatment based on this permission.
                                         if (!restrictionExempt && !restrictionApplied) {
@@ -2621,7 +2637,8 @@
                                         flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
                                         wasChanged = true;
                                     // Hard restricted permissions cannot be held.
-                                    } else if (!hardRestricted || restrictionExempt) {
+                                    } else if (!permissionPolicyInitialized ||
+                                            (!hardRestricted || restrictionExempt)) {
                                         if (permissionsState.grantRuntimePermission(bp, userId) !=
                                                 PERMISSION_OPERATION_FAILURE) {
                                              wasChanged = true;
@@ -2637,22 +2654,25 @@
 
                                     // If legacy app always grant the permission but if restricted
                                     // and not exempt take a note a restriction should be applied.
-                                    if ((hardRestricted || softRestricted)
-                                            && !restrictionExempt && !restrictionApplied) {
+                                    if (permissionPolicyInitialized
+                                            && (hardRestricted || softRestricted)
+                                                    && !restrictionExempt && !restrictionApplied) {
                                         flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
                                         wasChanged = true;
                                     }
                                 }
 
                                 // If unrestricted or restriction exempt, don't apply restriction.
-                                if (!(hardRestricted || softRestricted) || restrictionExempt)  {
-                                    if (restrictionApplied) {
-                                        flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
-                                        // Dropping restriction on a legacy app requires a review.
-                                        if (!appSupportsRuntimePermissions) {
-                                            flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+                                if (permissionPolicyInitialized) {
+                                    if (!(hardRestricted || softRestricted) || restrictionExempt) {
+                                        if (restrictionApplied) {
+                                            flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
+                                            // Dropping restriction on a legacy app implies a review
+                                            if (!appSupportsRuntimePermissions) {
+                                                flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+                                            }
+                                            wasChanged = true;
                                         }
-                                        wasChanged = true;
                                     }
                                 }
 
@@ -3910,7 +3930,7 @@
             throw new IllegalArgumentException("Invalid userId " + userId);
         }
         if (checkShell) {
-            PackageManagerServiceUtils.enforceShellRestriction(
+            PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
                     UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
         }
         if (!requirePermissionWhenSameUser && userId == UserHandle.getUserId(callingUid)) return;
@@ -3959,6 +3979,7 @@
         }
 
         mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
+        mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
 
         int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
         for (int userId : UserManagerService.getInstance().getUserIds()) {
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
index 7760c1e..6084c67 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.content.Intent;
 
 /**
@@ -26,6 +27,19 @@
 public abstract class PermissionPolicyInternal {
 
     /**
+     * Callback for initializing the permission policy service.
+     */
+    public interface OnInitializedCallback {
+
+        /**
+         * Called when initialized for the given user.
+         *
+         * @param userId The initialized user.
+         */
+        void onInitialized(@UserIdInt int userId);
+    }
+
+    /**
      * Check whether an activity should be started.
      *
      * @param intent the {@link Intent} for the activity start
@@ -36,4 +50,17 @@
      */
     public abstract boolean checkStartActivity(@NonNull Intent intent, int callingUid,
             @Nullable String callingPackage);
+
+    /**
+     * @return Whether the policy is initialized for a user.
+     */
+    public abstract boolean isInitialized(@UserIdInt int userId);
+
+    /**
+     * Set a callback for users being initialized. If the user is already
+     * initialized the callback will not be invoked.
+     *
+     * @param callback The callback to register.
+     */
+    public abstract void setOnInitializedCallback(@NonNull OnInitializedCallback callback);
 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 8da7f7b..f68a06b 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -66,6 +66,7 @@
 import com.android.server.SystemService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
+import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 
@@ -86,6 +87,10 @@
     @GuardedBy("mLock")
     private final SparseBooleanArray mIsStarted = new SparseBooleanArray();
 
+    /** Callbacks for when a user is initialized */
+    @GuardedBy("mLock")
+    private OnInitializedCallback mOnInitializedCallback;
+
     /**
      * Whether an async {@link #synchronizePackagePermissionsAndAppOpsForUser} is currently
      * scheduled for a package/user.
@@ -240,12 +245,20 @@
 
         grantOrUpgradeDefaultRuntimePermissionsIfNeeded(userId);
 
+        final OnInitializedCallback callback;
+
         synchronized (mLock) {
             mIsStarted.put(userId, true);
+            callback = mOnInitializedCallback;
         }
 
         // Force synchronization as permissions might have changed
         synchronizePermissionsAndAppOpsForUser(userId);
+
+        // Tell observers we are initialized for this user.
+        if (callback != null) {
+            callback.onInitialized(userId);
+        }
     }
 
     @Override
@@ -809,6 +822,18 @@
             return true;
         }
 
+        @Override
+        public boolean isInitialized(int userId) {
+            return isStarted(userId);
+        }
+
+        @Override
+        public void setOnInitializedCallback(@NonNull OnInitializedCallback callback) {
+            synchronized (mLock) {
+                mOnInitializedCallback = callback;
+            }
+        }
+
         /**
          * Check if the intent action is removed for the calling package (often based on target SDK
          * version). If the action is removed, we'll silently cancel the activity launch.
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index 56d8396..4e9b724 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -161,7 +161,7 @@
 
         context.getContentResolver().registerContentObserver(Settings.System.getUriFor(
                 Settings.System.ADAPTIVE_SLEEP),
-                false, new ContentObserver(new Handler()) {
+                false, new ContentObserver(new Handler(context.getMainLooper())) {
                     @Override
                     public void onChange(boolean selfChange) {
                         updateEnabledFromSettings(context);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d599441..e57f436 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2723,6 +2723,14 @@
                 return true;
             }
         }
+
+        if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
+                && mDisplayPowerRequest.dozeScreenState == Display.STATE_ON) {
+            // Although we are in DOZE and would normally allow the device to suspend,
+            // the doze service has explicitly requested the display to remain in the ON
+            // state which means we should hold the display suspend blocker.
+            return true;
+        }
         if (mScreenBrightnessBoostInProgress) {
             return true;
         }
@@ -4854,7 +4862,8 @@
         }
     }
 
-    private final class LocalService extends PowerManagerInternal {
+    @VisibleForTesting
+    final class LocalService extends PowerManagerInternal {
         @Override
         public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) {
             if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 1552fd5..491c5ab 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -38,11 +38,13 @@
 import android.os.ShellCommand;
 import android.os.Temperature;
 import android.util.ArrayMap;
+import android.util.EventLog;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
+import com.android.server.EventLogTags;
 import com.android.server.FgThread;
 import com.android.server.SystemService;
 
@@ -250,6 +252,8 @@
         } finally {
             mThermalEventListeners.finishBroadcast();
         }
+        EventLog.writeEvent(EventLogTags.THERMAL_CHANGED, temperature.getName(),
+                temperature.getType(), temperature.getValue(), temperature.getStatus(), mStatus);
     }
 
     private void shutdownIfNeeded(Temperature temperature) {
@@ -860,10 +864,10 @@
                     mThermalHal11.linkToDeath(new DeathRecipient(),
                             THERMAL_HAL_DEATH_COOKIE);
                     mThermalHal11.registerThermalCallback(mThermalCallback11);
+                    Slog.i(TAG, "Thermal HAL 1.1 service connected, limited thermal functions "
+                            + "due to legacy API.");
                 } catch (NoSuchElementException | RemoteException e) {
-                    Slog.e(TAG,
-                            "Thermal HAL 1.1 service not connected, no thermal call back will be "
-                                    + "called.");
+                    Slog.e(TAG, "Thermal HAL 1.1 service not connected.");
                     mThermalHal11 = null;
                 }
                 return (mThermalHal11 != null);
@@ -978,8 +982,9 @@
                     mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
                     mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
                             0 /* not used */);
+                    Slog.i(TAG, "Thermal HAL 2.0 service connected.");
                 } catch (NoSuchElementException | RemoteException e) {
-                    Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1.");
+                    Slog.e(TAG, "Thermal HAL 2.0 service not connected.");
                     mThermalHal20 = null;
                 }
                 return (mThermalHal20 != null);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 1948b20..bf8c042 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -264,9 +264,10 @@
         //TODO gradually add more role migrations statements here for remaining roles
         // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
         // for a given role before adding a migration statement for it here
-        maybeMigrateRole(RoleManager.ROLE_SMS, userId);
         maybeMigrateRole(RoleManager.ROLE_ASSISTANT, userId);
+        maybeMigrateRole(RoleManager.ROLE_BROWSER, userId);
         maybeMigrateRole(RoleManager.ROLE_DIALER, userId);
+        maybeMigrateRole(RoleManager.ROLE_SMS, userId);
         maybeMigrateRole(RoleManager.ROLE_EMERGENCY, userId);
 
         // Some package state has changed, so grant default roles again.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 828f790..d67048f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -841,7 +841,8 @@
 
     @Override
     public void setImeWindowStatus(int displayId, final IBinder token, final int vis,
-            final int backDisposition, final boolean showImeSwitcher) {
+            final int backDisposition, final boolean showImeSwitcher,
+            boolean isMultiClientImeEnabled) {
         enforceStatusBar();
 
         if (SPEW) {
@@ -858,7 +859,8 @@
                 if (mBar == null) return;
                 try {
                     mBar.setImeWindowStatus(
-                            displayId, token, vis, backDisposition, showImeSwitcher);
+                            displayId, token, vis, backDisposition, showImeSwitcher,
+                            isMultiClientImeEnabled);
                 } catch (RemoteException ex) { }
             });
         }
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index ab3d7b7..89a5305 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -457,12 +457,12 @@
             Preconditions.checkArgument(userId != UserHandle.USER_NULL, "Null userId");
             final int callingUserId = UserHandle.getCallingUserId();
             if (callingUserId != userId) {
-                context.enforceCallingPermission(
+                context.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                         "Invalid userId. UserId=" + userId + ", CallingUserId=" + callingUserId);
             }
         } catch (Exception e) {
-            throw new RemoteException("Invalid request", e,
+            throw new RemoteException("Invalid request: " + e.getMessage(), e,
                     /* enableSuppression */ true, /* writableStackTrace */ true);
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 015464e..31e8bbdab 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -30,6 +30,7 @@
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
+import static android.app.ActivityOptions.ANIM_UNDEFINED;
 import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.AppOpsManager.MODE_ALLOWED;
@@ -2096,6 +2097,7 @@
                         pendingOptions.getRemoteAnimationAdapter());
                 break;
             case ANIM_NONE:
+            case ANIM_UNDEFINED:
                 break;
             default:
                 Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a334ed8..9ed93c4 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -187,6 +187,7 @@
     private boolean mNoAnimation;
     private boolean mKeepCurTransition;
     private boolean mAvoidMoveToFront;
+    private boolean mFrozeTaskList;
 
     // We must track when we deliver the new intent since multiple code paths invoke
     // {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -483,6 +484,7 @@
         mNoAnimation = starter.mNoAnimation;
         mKeepCurTransition = starter.mKeepCurTransition;
         mAvoidMoveToFront = starter.mAvoidMoveToFront;
+        mFrozeTaskList = starter.mFrozeTaskList;
 
         mVoiceSession = starter.mVoiceSession;
         mVoiceInteractor = starter.mVoiceInteractor;
@@ -1093,6 +1095,14 @@
 
     void postStartActivityProcessing(ActivityRecord r, int result,
             ActivityStack startedActivityStack) {
+        if (!ActivityManager.isStartResultSuccessful(result)) {
+            if (mFrozeTaskList) {
+                // If we specifically froze the task list as part of starting an activity, then
+                // reset the frozen list state if it failed to start. This is normally otherwise
+                // called when the freeze-timeout has elapsed.
+                mSupervisor.mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
+            }
+        }
         if (ActivityManager.isStartResultFatalError(result)) {
             return;
         }
@@ -1485,6 +1495,14 @@
                 mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
                         : DEFAULT_DISPLAY;
 
+        // If requested, freeze the task list
+        if (mOptions != null && mOptions.freezeRecentTasksReordering()
+                && mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
+                && !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
+            mFrozeTaskList = true;
+            mSupervisor.mRecentTasks.setFreezeTaskListReordering();
+        }
+
         // Do not start home activity if it cannot be launched on preferred display. We are not
         // doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
         // fallback to launch on other displays.
@@ -1776,6 +1794,7 @@
         mNoAnimation = false;
         mKeepCurTransition = false;
         mAvoidMoveToFront = false;
+        mFrozeTaskList = false;
 
         mVoiceSession = null;
         mVoiceInteractor = null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b351faf..20ccfa8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -84,7 +84,6 @@
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
-import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -226,7 +225,6 @@
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
 import android.view.WindowManager;
-import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -263,6 +261,7 @@
 import com.android.server.am.UserState;
 import com.android.server.appop.AppOpsService;
 import com.android.server.firewall.IntentFirewall;
+import com.android.server.inputmethod.InputMethodSystemProperty;
 import com.android.server.pm.UserManagerService;
 import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -1618,8 +1617,9 @@
                     // Explicitly dismissing the activity so reset its relaunch flag.
                     r.mRelaunchReason = RELAUNCH_REASON_NONE;
                 } else {
-                    res = r.finishActivityLocked(resultCode, resultData, "app-request",
-                            true /* oomAdj */) != FINISH_RESULT_CANCELLED;
+                    r.finishActivityLocked(resultCode, resultData, "app-request",
+                            true /* oomAdj */);
+                    res = r.finishing;
                     if (!res) {
                         Slog.i(TAG, "Failed to finish by app-request");
                     }
@@ -6487,6 +6487,7 @@
                     }
                     return;
                 }
+                process.mIsImeProcess = true;
                 process.registerDisplayConfigurationListenerLocked(activityDisplay);
             }
         }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index aefc152..7fde6de 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -207,6 +207,7 @@
     boolean removed;
 
     // Information about an application starting window if displayed.
+    // Note: these are de-referenced before the starting window animates away.
     StartingData mStartingData;
     WindowState startingWindow;
     StartingSurface startingSurface;
@@ -1249,6 +1250,21 @@
         return true;
     }
 
+    /**
+     * @return {@code true} if starting window is in app's hierarchy.
+     */
+    boolean hasStartingWindow() {
+        if (startingDisplayed || mStartingData != null) {
+            return true;
+        }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            if (getChildAt(i).mAttrs.type == TYPE_APPLICATION_STARTING) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     void addWindow(WindowState w) {
         super.addWindow(w);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index faf75b6..4f4da4c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4871,9 +4871,13 @@
         //
         // In the case where we have no IME target we assign it where it's base layer would
         // place it in the AboveAppWindowContainers.
-        if (imeTarget != null && !(imeTarget.inSplitScreenWindowingMode()
-                || imeTarget.mToken.isAppAnimating())
-                && (imeTarget.getSurfaceControl() != null)) {
+        //
+        // Keep IME window in mAboveAppWindowsContainers as long as app's starting window exists
+        // so it get's layered above the starting window.
+        if (imeTarget != null
+                && !(imeTarget.mAppToken != null && imeTarget.mAppToken.hasStartingWindow())
+                && (!(imeTarget.inSplitScreenWindowingMode() || imeTarget.mToken.isAppAnimating())
+                && (imeTarget.getSurfaceControl() != null))) {
             mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
                     // TODO: We need to use an extra level on the app surface to ensure
                     // this is always above SurfaceView but always below attached window.
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 553b0ff..c8f7af5 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -147,12 +147,6 @@
         return mIsClosing;
     }
 
-    private void hideInputSurface() {
-        if (mInputSurface != null) {
-            mTransaction.hide(mInputSurface).apply();
-        }
-    }
-
     private void showInputSurface() {
         if (mInputSurface == null) {
             mInputSurface = mService.makeSurfaceBuilder(
@@ -198,8 +192,6 @@
             mInputInterceptor = null;
         }
 
-        hideInputSurface();
-
         // Send drag end broadcast if drag start has been sent.
         if (mDragInProgress) {
             final int myPid = Process.myPid();
@@ -239,6 +231,10 @@
         }
 
         // Clear the internal variables.
+        if (mInputSurface != null) {
+            mTransaction.remove(mInputSurface).apply();
+            mInputSurface = null;
+        }
         if (mSurfaceControl != null) {
             mTransaction.reparent(mSurfaceControl, null).apply();
             mSurfaceControl = null;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index b94a7dc..cb15f57 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -42,184 +42,54 @@
 import java.io.PrintWriter;
 
 class ScreenRotationAnimation {
-    static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenRotationAnimation" : TAG_WM;
-    static final boolean DEBUG_STATE = false;
-    static final boolean DEBUG_TRANSFORMS = false;
-    static final boolean TWO_PHASE_ANIMATION = false;
-    static final boolean USE_CUSTOM_BLACK_FRAME = false;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenRotationAnimation" : TAG_WM;
 
     /*
      * Layers for screen rotation animation. We put these layers above
      * WINDOW_FREEZE_LAYER so that screen freeze will cover all windows.
      */
-    static final int SCREEN_FREEZE_LAYER_BASE       = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
-    static final int SCREEN_FREEZE_LAYER_ENTER      = SCREEN_FREEZE_LAYER_BASE;
-    static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1;
-    static final int SCREEN_FREEZE_LAYER_EXIT       = SCREEN_FREEZE_LAYER_BASE + 2;
-    static final int SCREEN_FREEZE_LAYER_CUSTOM     = SCREEN_FREEZE_LAYER_BASE + 3;
+    private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
+    private static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE;
+    private static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1;
+    private static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2;
 
-    final Context mContext;
-    final DisplayContent mDisplayContent;
-    SurfaceControl mSurfaceControl;
-    BlackFrame mCustomBlackFrame;
-    BlackFrame mExitingBlackFrame;
-    BlackFrame mEnteringBlackFrame;
-    int mWidth, mHeight;
+    private final Context mContext;
+    private final DisplayContent mDisplayContent;
+    private final float[] mTmpFloats = new float[9];
+    private final Transformation mRotateExitTransformation = new Transformation();
+    private final Transformation mRotateEnterTransformation = new Transformation();
+    // Complete transformations being applied.
+    private final Transformation mExitTransformation = new Transformation();
+    private final Transformation mEnterTransformation = new Transformation();
+    private final Matrix mFrameInitialMatrix = new Matrix();
+    private final Matrix mSnapshotInitialMatrix = new Matrix();
+    private final Matrix mSnapshotFinalMatrix = new Matrix();
+    private final Matrix mExitFrameFinalMatrix = new Matrix();
+    private final WindowManagerService mService;
+    private SurfaceControl mSurfaceControl;
+    private BlackFrame mEnteringBlackFrame;
+    private int mWidth, mHeight;
 
-    int mOriginalRotation;
-    int mOriginalWidth, mOriginalHeight;
-    int mCurRotation;
-    Rect mOriginalDisplayRect = new Rect();
-    Rect mCurrentDisplayRect = new Rect();
+    private int mOriginalRotation;
+    private int mOriginalWidth, mOriginalHeight;
+    private int mCurRotation;
 
-    // For all animations, "exit" is for the UI elements that are going
-    // away (that is the snapshot of the old screen), and "enter" is for
-    // the new UI elements that are appearing (that is the active windows
-    // in their final orientation).
-
-    // The starting animation for the exiting and entering elements.  This
-    // animation applies a transformation while the rotation is in progress.
-    // It is started immediately, before the new entering UI is ready.
-    Animation mStartExitAnimation;
-    final Transformation mStartExitTransformation = new Transformation();
-    Animation mStartEnterAnimation;
-    final Transformation mStartEnterTransformation = new Transformation();
-    Animation mStartFrameAnimation;
-    final Transformation mStartFrameTransformation = new Transformation();
-
-    // The finishing animation for the exiting and entering elements.  This
-    // animation needs to undo the transformation of the starting animation.
-    // It starts running once the new rotation UI elements are ready to be
-    // displayed.
-    Animation mFinishExitAnimation;
-    final Transformation mFinishExitTransformation = new Transformation();
-    Animation mFinishEnterAnimation;
-    final Transformation mFinishEnterTransformation = new Transformation();
-    Animation mFinishFrameAnimation;
-    final Transformation mFinishFrameTransformation = new Transformation();
-
+    private Rect mOriginalDisplayRect = new Rect();
+    private Rect mCurrentDisplayRect = new Rect();
     // The current active animation to move from the old to the new rotated
     // state.  Which animation is run here will depend on the old and new
     // rotations.
-    Animation mRotateExitAnimation;
-    final Transformation mRotateExitTransformation = new Transformation();
-    Animation mRotateEnterAnimation;
-    final Transformation mRotateEnterTransformation = new Transformation();
-    Animation mRotateFrameAnimation;
-    final Transformation mRotateFrameTransformation = new Transformation();
-
-    // A previously running rotate animation.  This will be used if we need
-    // to switch to a new rotation before finishing the previous one.
-    Animation mLastRotateExitAnimation;
-    final Transformation mLastRotateExitTransformation = new Transformation();
-    Animation mLastRotateEnterAnimation;
-    final Transformation mLastRotateEnterTransformation = new Transformation();
-    Animation mLastRotateFrameAnimation;
-    final Transformation mLastRotateFrameTransformation = new Transformation();
-
-    // Complete transformations being applied.
-    final Transformation mExitTransformation = new Transformation();
-    final Transformation mEnterTransformation = new Transformation();
-    final Transformation mFrameTransformation = new Transformation();
-
-    boolean mStarted;
-    boolean mAnimRunning;
-    boolean mFinishAnimReady;
-    long mFinishAnimStartTime;
-    boolean mForceDefaultOrientation;
-
-    final Matrix mFrameInitialMatrix = new Matrix();
-    final Matrix mSnapshotInitialMatrix = new Matrix();
-    final Matrix mSnapshotFinalMatrix = new Matrix();
-    final Matrix mExitFrameFinalMatrix = new Matrix();
-    final Matrix mTmpMatrix = new Matrix();
-    final float[] mTmpFloats = new float[9];
+    private Animation mRotateExitAnimation;
+    private Animation mRotateEnterAnimation;
+    private boolean mStarted;
+    private boolean mAnimRunning;
+    private boolean mFinishAnimReady;
+    private long mFinishAnimStartTime;
+    private boolean mForceDefaultOrientation;
+    private BlackFrame mExitingBlackFrame;
     private boolean mMoreRotateEnter;
     private boolean mMoreRotateExit;
-    private boolean mMoreRotateFrame;
-    private boolean mMoreFinishEnter;
-    private boolean mMoreFinishExit;
-    private boolean mMoreFinishFrame;
-    private boolean mMoreStartEnter;
-    private boolean mMoreStartExit;
-    private boolean mMoreStartFrame;
-    long mHalfwayPoint;
-
-    private final WindowManagerService mService;
-
-    public void printTo(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
-                pw.print(" mWidth="); pw.print(mWidth);
-                pw.print(" mHeight="); pw.println(mHeight);
-        if (USE_CUSTOM_BLACK_FRAME) {
-            pw.print(prefix); pw.print("mCustomBlackFrame="); pw.println(mCustomBlackFrame);
-            if (mCustomBlackFrame != null) {
-                mCustomBlackFrame.printTo(prefix + "  ", pw);
-            }
-        }
-        pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame);
-        if (mExitingBlackFrame != null) {
-            mExitingBlackFrame.printTo(prefix + "  ", pw);
-        }
-        pw.print(prefix); pw.print("mEnteringBlackFrame="); pw.println(mEnteringBlackFrame);
-        if (mEnteringBlackFrame != null) {
-            mEnteringBlackFrame.printTo(prefix + "  ", pw);
-        }
-        pw.print(prefix); pw.print("mCurRotation="); pw.print(mCurRotation);
-                pw.print(" mOriginalRotation="); pw.println(mOriginalRotation);
-        pw.print(prefix); pw.print("mOriginalWidth="); pw.print(mOriginalWidth);
-                pw.print(" mOriginalHeight="); pw.println(mOriginalHeight);
-        pw.print(prefix); pw.print("mStarted="); pw.print(mStarted);
-                pw.print(" mAnimRunning="); pw.print(mAnimRunning);
-                pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady);
-                pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime);
-        pw.print(prefix); pw.print("mStartExitAnimation="); pw.print(mStartExitAnimation);
-                pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation);
-                pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mStartFrameAnimation="); pw.print(mStartFrameAnimation);
-                pw.print(" "); mStartFrameTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation);
-                pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation);
-                pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mFinishFrameAnimation="); pw.print(mFinishFrameAnimation);
-                pw.print(" "); mFinishFrameTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation);
-                pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
-                pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mRotateFrameAnimation="); pw.print(mRotateFrameAnimation);
-                pw.print(" "); mRotateFrameTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mExitTransformation=");
-                mExitTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mEnterTransformation=");
-                mEnterTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mFrameTransformation=");
-                mFrameTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mFrameInitialMatrix=");
-                mFrameInitialMatrix.printShortString(pw);
-                pw.println();
-        pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
-                mSnapshotInitialMatrix.printShortString(pw);
-                pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
-                pw.println();
-        pw.print(prefix); pw.print("mExitFrameFinalMatrix=");
-                mExitFrameFinalMatrix.printShortString(pw);
-                pw.println();
-        pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
-        if (mForceDefaultOrientation) {
-            pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString());
-            pw.print(" mCurrentDisplayRect="); pw.println(mCurrentDisplayRect.toShortString());
-        }
-    }
-
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-        proto.write(STARTED, mStarted);
-        proto.write(ANIMATION_RUNNING, mAnimRunning);
-        proto.end(token);
-    }
+    private long mHalfwayPoint;
 
     public ScreenRotationAnimation(Context context, DisplayContent displayContent,
             boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) {
@@ -276,7 +146,7 @@
             final Surface surface = mService.mSurfaceFactory.make();
             surface.copyFrom(mSurfaceControl);
             SurfaceControl.ScreenshotGraphicBuffer gb =
-                mService.mDisplayManagerInternal.screenshot(displayId);
+                    mService.mDisplayManagerInternal.screenshot(displayId);
             if (gb != null) {
                 try {
                     surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
@@ -301,12 +171,42 @@
             Slog.w(TAG, "Unable to allocate freeze surface", e);
         }
 
-        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
-                "  FREEZE " + mSurfaceControl + ": CREATE");
+        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+            Slog.i(TAG_WM,
+                    "  FREEZE " + mSurfaceControl + ": CREATE");
+        }
         setRotation(t, originalRotation);
         t.apply();
     }
 
+    private static void createRotationMatrix(int rotation, int width, int height,
+            Matrix outMatrix) {
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                outMatrix.reset();
+                break;
+            case Surface.ROTATION_90:
+                outMatrix.setRotate(90, 0, 0);
+                outMatrix.postTranslate(height, 0);
+                break;
+            case Surface.ROTATION_180:
+                outMatrix.setRotate(180, 0, 0);
+                outMatrix.postTranslate(width, height);
+                break;
+            case Surface.ROTATION_270:
+                outMatrix.setRotate(270, 0, 0);
+                outMatrix.postTranslate(0, width);
+                break;
+        }
+    }
+
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(STARTED, mStarted);
+        proto.write(ANIMATION_RUNNING, mAnimRunning);
+        proto.end(token);
+    }
+
     boolean hasScreenshot() {
         return mSurfaceControl != null;
     }
@@ -326,40 +226,55 @@
                     mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                     mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
             t.setAlpha(mSurfaceControl, alpha);
-            if (DEBUG_TRANSFORMS) {
-                float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
-                float[] dstPnts = new float[4];
-                matrix.mapPoints(dstPnts, srcPnts);
-                Slog.i(TAG, "Original  : (" + srcPnts[0] + "," + srcPnts[1]
-                        + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
-                Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
-                        + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
-            }
         }
     }
 
-    public static void createRotationMatrix(int rotation, int width, int height,
-            Matrix outMatrix) {
-        switch (rotation) {
-            case Surface.ROTATION_0:
-                outMatrix.reset();
-                break;
-            case Surface.ROTATION_90:
-                outMatrix.setRotate(90, 0, 0);
-                outMatrix.postTranslate(height, 0);
-                break;
-            case Surface.ROTATION_180:
-                outMatrix.setRotate(180, 0, 0);
-                outMatrix.postTranslate(width, height);
-                break;
-            case Surface.ROTATION_270:
-                outMatrix.setRotate(270, 0, 0);
-                outMatrix.postTranslate(0, width);
-                break;
+    public void printTo(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
+        pw.print(" mWidth="); pw.print(mWidth);
+        pw.print(" mHeight="); pw.println(mHeight);
+        pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame);
+        if (mExitingBlackFrame != null) {
+            mExitingBlackFrame.printTo(prefix + "  ", pw);
+        }
+        pw.print(prefix); pw.print("mEnteringBlackFrame="); pw.println(mEnteringBlackFrame);
+        if (mEnteringBlackFrame != null) {
+            mEnteringBlackFrame.printTo(prefix + "  ", pw);
+        }
+        pw.print(prefix); pw.print("mCurRotation="); pw.print(mCurRotation);
+        pw.print(" mOriginalRotation="); pw.println(mOriginalRotation);
+        pw.print(prefix); pw.print("mOriginalWidth="); pw.print(mOriginalWidth);
+        pw.print(" mOriginalHeight="); pw.println(mOriginalHeight);
+        pw.print(prefix); pw.print("mStarted="); pw.print(mStarted);
+        pw.print(" mAnimRunning="); pw.print(mAnimRunning);
+        pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady);
+        pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime);
+        pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation);
+        pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
+        pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mExitTransformation=");
+        mExitTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mEnterTransformation=");
+        mEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mFrameInitialMatrix=");
+        mFrameInitialMatrix.printShortString(pw);
+        pw.println();
+        pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
+        mSnapshotInitialMatrix.printShortString(pw);
+        pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
+        pw.println();
+        pw.print(prefix); pw.print("mExitFrameFinalMatrix=");
+        mExitFrameFinalMatrix.printShortString(pw);
+        pw.println();
+        pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
+        if (mForceDefaultOrientation) {
+            pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString());
+            pw.print(" mCurrentDisplayRect="); pw.println(mCurrentDisplayRect.toShortString());
         }
     }
 
-    private void setRotation(SurfaceControl.Transaction t, int rotation) {
+    public void setRotation(SurfaceControl.Transaction t, int rotation) {
         mCurRotation = rotation;
 
         // Compute the transformation matrix that must be applied
@@ -368,17 +283,12 @@
         int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
         createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
 
-        if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
         setSnapshotTransform(t, mSnapshotInitialMatrix, 1.0f);
     }
 
     public boolean setRotation(SurfaceControl.Transaction t, int rotation,
             long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) {
         setRotation(t, rotation);
-        if (TWO_PHASE_ANIMATION) {
-            return startAnimation(t, maxAnimationDuration, animationScale,
-                    finalWidth, finalHeight, false, 0, 0);
-        }
 
         // Don't start animation yet.
         return false;
@@ -400,37 +310,9 @@
 
         mStarted = true;
 
-        boolean firstStart = false;
-
         // Figure out how the screen has moved from the original rotation.
         int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
 
-        if (TWO_PHASE_ANIMATION && mFinishExitAnimation == null
-                && (!dismissing || delta != Surface.ROTATION_0)) {
-            if (DEBUG_STATE) Slog.v(TAG, "Creating start and finish animations");
-            firstStart = true;
-            mStartExitAnimation = AnimationUtils.loadAnimation(mContext,
-                    com.android.internal.R.anim.screen_rotate_start_exit);
-            mStartEnterAnimation = AnimationUtils.loadAnimation(mContext,
-                    com.android.internal.R.anim.screen_rotate_start_enter);
-            if (USE_CUSTOM_BLACK_FRAME) {
-                mStartFrameAnimation = AnimationUtils.loadAnimation(mContext,
-                        com.android.internal.R.anim.screen_rotate_start_frame);
-            }
-            mFinishExitAnimation = AnimationUtils.loadAnimation(mContext,
-                    com.android.internal.R.anim.screen_rotate_finish_exit);
-            mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext,
-                    com.android.internal.R.anim.screen_rotate_finish_enter);
-            if (USE_CUSTOM_BLACK_FRAME) {
-                mFinishFrameAnimation = AnimationUtils.loadAnimation(mContext,
-                        com.android.internal.R.anim.screen_rotate_finish_frame);
-            }
-        }
-
-        if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth="
-                + finalWidth + " finalHeight=" + finalHeight
-                + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight);
-
         final boolean customAnim;
         if (exitAnim != 0 && enterAnim != 0) {
             customAnim = true;
@@ -444,40 +326,24 @@
                             com.android.internal.R.anim.screen_rotate_0_exit);
                     mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                             com.android.internal.R.anim.screen_rotate_0_enter);
-                    if (USE_CUSTOM_BLACK_FRAME) {
-                        mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
-                                com.android.internal.R.anim.screen_rotate_0_frame);
-                    }
                     break;
                 case Surface.ROTATION_90:
                     mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                             com.android.internal.R.anim.screen_rotate_plus_90_exit);
                     mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                             com.android.internal.R.anim.screen_rotate_plus_90_enter);
-                    if (USE_CUSTOM_BLACK_FRAME) {
-                        mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
-                                com.android.internal.R.anim.screen_rotate_plus_90_frame);
-                    }
                     break;
                 case Surface.ROTATION_180:
                     mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                             com.android.internal.R.anim.screen_rotate_180_exit);
                     mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                             com.android.internal.R.anim.screen_rotate_180_enter);
-                    if (USE_CUSTOM_BLACK_FRAME) {
-                        mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
-                                com.android.internal.R.anim.screen_rotate_180_frame);
-                    }
                     break;
                 case Surface.ROTATION_270:
                     mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                             com.android.internal.R.anim.screen_rotate_minus_90_exit);
                     mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                             com.android.internal.R.anim.screen_rotate_minus_90_enter);
-                    if (USE_CUSTOM_BLACK_FRAME) {
-                        mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
-                                com.android.internal.R.anim.screen_rotate_minus_90_frame);
-                    }
                     break;
             }
         }
@@ -486,85 +352,16 @@
         // means to allow supplying the last and next size.  In this definition
         // "%p" is the original (let's call it "previous") size, and "%" is the
         // screen's current/new size.
-        if (TWO_PHASE_ANIMATION && firstStart) {
-            // Compute partial steps between original and final sizes.  These
-            // are used for the dimensions of the exiting and entering elements,
-            // so they are never stretched too significantly.
-            final int halfWidth = (finalWidth + mOriginalWidth) / 2;
-            final int halfHeight = (finalHeight + mOriginalHeight) / 2;
-
-            if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations");
-            mStartEnterAnimation.initialize(finalWidth, finalHeight,
-                    halfWidth, halfHeight);
-            mStartExitAnimation.initialize(halfWidth, halfHeight,
-                    mOriginalWidth, mOriginalHeight);
-            mFinishEnterAnimation.initialize(finalWidth, finalHeight,
-                    halfWidth, halfHeight);
-            mFinishExitAnimation.initialize(halfWidth, halfHeight,
-                    mOriginalWidth, mOriginalHeight);
-            if (USE_CUSTOM_BLACK_FRAME) {
-                mStartFrameAnimation.initialize(finalWidth, finalHeight,
-                        mOriginalWidth, mOriginalHeight);
-                mFinishFrameAnimation.initialize(finalWidth, finalHeight,
-                        mOriginalWidth, mOriginalHeight);
-            }
-        }
         mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
         mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
-        if (USE_CUSTOM_BLACK_FRAME) {
-            mRotateFrameAnimation.initialize(finalWidth, finalHeight, mOriginalWidth,
-                    mOriginalHeight);
-        }
         mAnimRunning = false;
         mFinishAnimReady = false;
         mFinishAnimStartTime = -1;
 
-        if (TWO_PHASE_ANIMATION && firstStart) {
-            mStartExitAnimation.restrictDuration(maxAnimationDuration);
-            mStartExitAnimation.scaleCurrentDuration(animationScale);
-            mStartEnterAnimation.restrictDuration(maxAnimationDuration);
-            mStartEnterAnimation.scaleCurrentDuration(animationScale);
-            mFinishExitAnimation.restrictDuration(maxAnimationDuration);
-            mFinishExitAnimation.scaleCurrentDuration(animationScale);
-            mFinishEnterAnimation.restrictDuration(maxAnimationDuration);
-            mFinishEnterAnimation.scaleCurrentDuration(animationScale);
-            if (USE_CUSTOM_BLACK_FRAME) {
-                mStartFrameAnimation.restrictDuration(maxAnimationDuration);
-                mStartFrameAnimation.scaleCurrentDuration(animationScale);
-                mFinishFrameAnimation.restrictDuration(maxAnimationDuration);
-                mFinishFrameAnimation.scaleCurrentDuration(animationScale);
-            }
-        }
         mRotateExitAnimation.restrictDuration(maxAnimationDuration);
         mRotateExitAnimation.scaleCurrentDuration(animationScale);
         mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
         mRotateEnterAnimation.scaleCurrentDuration(animationScale);
-        if (USE_CUSTOM_BLACK_FRAME) {
-            mRotateFrameAnimation.restrictDuration(maxAnimationDuration);
-            mRotateFrameAnimation.scaleCurrentDuration(animationScale);
-        }
-
-        final int layerStack = mDisplayContent.getDisplay().getLayerStack();
-        if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
-            // Compute the transformation matrix that must be applied
-            // the the black frame to make it stay in the initial position
-            // before the new screen rotation.  This is different than the
-            // snapshot transformation because the snapshot is always based
-            // of the native orientation of the screen, not the orientation
-            // we were last in.
-            createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
-
-            try {
-                Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
-                        mOriginalWidth*2, mOriginalHeight*2);
-                Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
-                mCustomBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
-                        SCREEN_FREEZE_LAYER_CUSTOM, mDisplayContent, false);
-                mCustomBlackFrame.setMatrix(t, mFrameInitialMatrix);
-            } catch (OutOfResourcesException e) {
-                Slog.w(TAG, "Unable to allocate black surface", e);
-            }
-        }
 
         if (!customAnim && mExitingBlackFrame == null) {
             try {
@@ -585,8 +382,8 @@
                     outer = mCurrentDisplayRect;
                     inner = mOriginalDisplayRect;
                 } else {
-                    outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
-                            mOriginalWidth*2, mOriginalHeight*2);
+                    outer = new Rect(-mOriginalWidth * 1, -mOriginalHeight * 1,
+                            mOriginalWidth * 2, mOriginalHeight * 2);
                     inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
                 }
                 mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
@@ -599,8 +396,8 @@
 
         if (customAnim && mEnteringBlackFrame == null) {
             try {
-                Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
-                        finalWidth*2, finalHeight*2);
+                Rect outer = new Rect(-finalWidth * 1, -finalHeight * 1,
+                        finalWidth * 2, finalHeight * 2);
                 Rect inner = new Rect(0, 0, finalWidth, finalHeight);
                 mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
                         SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false);
@@ -617,7 +414,6 @@
      */
     public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
             float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
-        if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
         if (mSurfaceControl == null) {
             // Can't do animation.
             return false;
@@ -629,24 +425,20 @@
         if (!mStarted) {
             return false;
         }
-        if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true");
         mFinishAnimReady = true;
         return true;
     }
 
     public void kill() {
-        if (DEBUG_STATE) Slog.v(TAG, "Kill!");
         if (mSurfaceControl != null) {
             if (SHOW_TRANSACTIONS ||
-                    SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
-                            "  FREEZE " + mSurfaceControl + ": DESTROY");
+                    SHOW_SURFACE_ALLOC) {
+                Slog.i(TAG_WM,
+                        "  FREEZE " + mSurfaceControl + ": DESTROY");
+            }
             mService.mTransactionFactory.make().remove(mSurfaceControl).apply();
             mSurfaceControl = null;
         }
-        if (mCustomBlackFrame != null) {
-            mCustomBlackFrame.kill();
-            mCustomBlackFrame = null;
-        }
         if (mExitingBlackFrame != null) {
             mExitingBlackFrame.kill();
             mExitingBlackFrame = null;
@@ -655,38 +447,6 @@
             mEnteringBlackFrame.kill();
             mEnteringBlackFrame = null;
         }
-        if (TWO_PHASE_ANIMATION) {
-            if (mStartExitAnimation != null) {
-                mStartExitAnimation.cancel();
-                mStartExitAnimation = null;
-            }
-            if (mStartEnterAnimation != null) {
-                mStartEnterAnimation.cancel();
-                mStartEnterAnimation = null;
-            }
-            if (mFinishExitAnimation != null) {
-                mFinishExitAnimation.cancel();
-                mFinishExitAnimation = null;
-            }
-            if (mFinishEnterAnimation != null) {
-                mFinishEnterAnimation.cancel();
-                mFinishEnterAnimation = null;
-            }
-        }
-        if (USE_CUSTOM_BLACK_FRAME) {
-            if (mStartFrameAnimation != null) {
-                mStartFrameAnimation.cancel();
-                mStartFrameAnimation = null;
-            }
-            if (mRotateFrameAnimation != null) {
-                mRotateFrameAnimation.cancel();
-                mRotateFrameAnimation = null;
-            }
-            if (mFinishFrameAnimation != null) {
-                mFinishFrameAnimation.cancel();
-                mFinishFrameAnimation = null;
-            }
-        }
         if (mRotateExitAnimation != null) {
             mRotateExitAnimation.cancel();
             mRotateExitAnimation = null;
@@ -698,7 +458,7 @@
     }
 
     public boolean isAnimating() {
-        return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady);
+        return hasAnimations();
     }
 
     public boolean isRotating() {
@@ -706,13 +466,7 @@
     }
 
     private boolean hasAnimations() {
-        return (TWO_PHASE_ANIMATION &&
-                    (mStartEnterAnimation != null || mStartExitAnimation != null
-                    || mFinishEnterAnimation != null || mFinishExitAnimation != null))
-                || (USE_CUSTOM_BLACK_FRAME &&
-                        (mStartFrameAnimation != null || mRotateFrameAnimation != null
-                        || mFinishFrameAnimation != null))
-                || mRotateEnterAnimation != null || mRotateExitAnimation != null;
+        return mRotateEnterAnimation != null || mRotateExitAnimation != null;
     }
 
     private boolean stepAnimation(long now) {
@@ -720,177 +474,45 @@
             mHalfwayPoint = Long.MAX_VALUE;
         }
         if (mFinishAnimReady && mFinishAnimStartTime < 0) {
-            if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
             mFinishAnimStartTime = now;
         }
 
-        if (TWO_PHASE_ANIMATION) {
-            mMoreStartExit = false;
-            if (mStartExitAnimation != null) {
-                mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
-                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
-            }
-
-            mMoreStartEnter = false;
-            if (mStartEnterAnimation != null) {
-                mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
-                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
-            }
-        }
-        if (USE_CUSTOM_BLACK_FRAME) {
-            mMoreStartFrame = false;
-            if (mStartFrameAnimation != null) {
-                mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
-                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
-            }
-        }
-
-        long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0;
-        if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);
-
-        if (TWO_PHASE_ANIMATION) {
-            mMoreFinishExit = false;
-            if (mFinishExitAnimation != null) {
-                mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
-                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
-            }
-
-            mMoreFinishEnter = false;
-            if (mFinishEnterAnimation != null) {
-                mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
-                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
-            }
-        }
-        if (USE_CUSTOM_BLACK_FRAME) {
-            mMoreFinishFrame = false;
-            if (mFinishFrameAnimation != null) {
-                mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
-                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
-            }
-        }
-
         mMoreRotateExit = false;
         if (mRotateExitAnimation != null) {
-            mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation);
+            mMoreRotateExit = mRotateExitAnimation.getTransformation(now,
+                    mRotateExitTransformation);
         }
 
         mMoreRotateEnter = false;
         if (mRotateEnterAnimation != null) {
-            mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
+            mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now,
+                    mRotateEnterTransformation);
         }
 
-        if (USE_CUSTOM_BLACK_FRAME) {
-            mMoreRotateFrame = false;
-            if (mRotateFrameAnimation != null) {
-                mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
-                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
-            }
-        }
-
-        if (!mMoreRotateExit && (!TWO_PHASE_ANIMATION || (!mMoreStartExit && !mMoreFinishExit))) {
-            if (TWO_PHASE_ANIMATION) {
-                if (mStartExitAnimation != null) {
-                    if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!");
-                    mStartExitAnimation.cancel();
-                    mStartExitAnimation = null;
-                    mStartExitTransformation.clear();
-                }
-                if (mFinishExitAnimation != null) {
-                    if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!");
-                    mFinishExitAnimation.cancel();
-                    mFinishExitAnimation = null;
-                    mFinishExitTransformation.clear();
-                }
-            }
+        if (!mMoreRotateExit) {
             if (mRotateExitAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!");
                 mRotateExitAnimation.cancel();
                 mRotateExitAnimation = null;
                 mRotateExitTransformation.clear();
             }
         }
 
-        if (!mMoreRotateEnter && (!TWO_PHASE_ANIMATION || (!mMoreStartEnter && !mMoreFinishEnter))) {
-            if (TWO_PHASE_ANIMATION) {
-                if (mStartEnterAnimation != null) {
-                    if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!");
-                    mStartEnterAnimation.cancel();
-                    mStartEnterAnimation = null;
-                    mStartEnterTransformation.clear();
-                }
-                if (mFinishEnterAnimation != null) {
-                    if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!");
-                    mFinishEnterAnimation.cancel();
-                    mFinishEnterAnimation = null;
-                    mFinishEnterTransformation.clear();
-                }
-            }
+        if (!mMoreRotateEnter) {
             if (mRotateEnterAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!");
                 mRotateEnterAnimation.cancel();
                 mRotateEnterAnimation = null;
                 mRotateEnterTransformation.clear();
             }
         }
 
-        if (USE_CUSTOM_BLACK_FRAME && !mMoreStartFrame && !mMoreRotateFrame && !mMoreFinishFrame) {
-            if (mStartFrameAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing start frame anim!");
-                mStartFrameAnimation.cancel();
-                mStartFrameAnimation = null;
-                mStartFrameTransformation.clear();
-            }
-            if (mFinishFrameAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing finish frame anim!");
-                mFinishFrameAnimation.cancel();
-                mFinishFrameAnimation = null;
-                mFinishFrameTransformation.clear();
-            }
-            if (mRotateFrameAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing rotate frame anim!");
-                mRotateFrameAnimation.cancel();
-                mRotateFrameAnimation = null;
-                mRotateFrameTransformation.clear();
-            }
-        }
-
         mExitTransformation.set(mRotateExitTransformation);
         mEnterTransformation.set(mRotateEnterTransformation);
-        if (TWO_PHASE_ANIMATION) {
-            mExitTransformation.compose(mStartExitTransformation);
-            mExitTransformation.compose(mFinishExitTransformation);
 
-            mEnterTransformation.compose(mStartEnterTransformation);
-            mEnterTransformation.compose(mFinishEnterTransformation);
-        }
-
-        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
-        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);
-
-        if (USE_CUSTOM_BLACK_FRAME) {
-            //mFrameTransformation.set(mRotateExitTransformation);
-            //mFrameTransformation.compose(mStartExitTransformation);
-            //mFrameTransformation.compose(mFinishExitTransformation);
-            mFrameTransformation.set(mRotateFrameTransformation);
-            mFrameTransformation.compose(mStartFrameTransformation);
-            mFrameTransformation.compose(mFinishFrameTransformation);
-            mFrameTransformation.getMatrix().preConcat(mFrameInitialMatrix);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation);
-        }
-
-        final boolean more = (TWO_PHASE_ANIMATION
-                    && (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit))
-                || (USE_CUSTOM_BLACK_FRAME
-                        && (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame))
-                || mMoreRotateEnter || mMoreRotateExit
+        final boolean more = mMoreRotateEnter || mMoreRotateExit
                 || !mFinishAnimReady;
 
         mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
 
-        if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more);
-
         return more;
     }
 
@@ -900,27 +522,17 @@
         }
 
         if (mSurfaceControl != null) {
-            if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
-                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface");
+            if (!mMoreRotateExit) {
                 t.hide(mSurfaceControl);
             }
         }
 
-        if (mCustomBlackFrame != null) {
-            if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) {
-                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame");
-                mCustomBlackFrame.hide(t);
-            } else {
-                mCustomBlackFrame.setMatrix(t, mFrameTransformation.getMatrix());
-            }
-        }
-
         if (mExitingBlackFrame != null) {
-            if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
-                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding exiting frame");
+            if (!mMoreRotateExit) {
                 mExitingBlackFrame.hide(t);
             } else {
-                mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix);
+                mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(),
+                        mFrameInitialMatrix);
                 mExitingBlackFrame.setMatrix(t, mExitFrameFinalMatrix);
                 if (mForceDefaultOrientation) {
                     mExitingBlackFrame.setAlpha(t, mExitTransformation.getAlpha());
@@ -929,8 +541,7 @@
         }
 
         if (mEnteringBlackFrame != null) {
-            if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) {
-                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding entering frame");
+            if (!mMoreRotateEnter) {
                 mEnteringBlackFrame.hide(t);
             } else {
                 mEnteringBlackFrame.setMatrix(t, mEnterTransformation.getMatrix());
@@ -943,38 +554,11 @@
 
     public boolean stepAnimationLocked(long now) {
         if (!hasAnimations()) {
-            if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
             mFinishAnimReady = false;
             return false;
         }
 
         if (!mAnimRunning) {
-            if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
-            if (TWO_PHASE_ANIMATION) {
-                if (mStartEnterAnimation != null) {
-                    mStartEnterAnimation.setStartTime(now);
-                }
-                if (mStartExitAnimation != null) {
-                    mStartExitAnimation.setStartTime(now);
-                }
-                if (mFinishEnterAnimation != null) {
-                    mFinishEnterAnimation.setStartTime(0);
-                }
-                if (mFinishExitAnimation != null) {
-                    mFinishExitAnimation.setStartTime(0);
-                }
-            }
-            if (USE_CUSTOM_BLACK_FRAME) {
-                if (mStartFrameAnimation != null) {
-                    mStartFrameAnimation.setStartTime(now);
-                }
-                if (mFinishFrameAnimation != null) {
-                    mFinishFrameAnimation.setStartTime(0);
-                }
-                if (mRotateFrameAnimation != null) {
-                    mRotateFrameAnimation.setStartTime(now);
-                }
-            }
             if (mRotateEnterAnimation != null) {
                 mRotateEnterAnimation.setStartTime(now);
             }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index cb50460..85176be 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -193,7 +193,9 @@
             public void onAnimationStart(Animator animation) {
                 synchronized (mCancelLock) {
                     if (!a.mCancelled) {
-                        mFrameTransaction.show(a.mLeash);
+                        // TODO: change this back to use show instead of alpha when b/138459974 is
+                        // fixed.
+                        mFrameTransaction.setAlpha(a.mLeash, 1);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 3d9dfeb..cd211a2 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -324,9 +324,9 @@
                 .setName(surface + " - animation-leash");
         final SurfaceControl leash = builder.build();
         t.setWindowCrop(leash, width, height);
-        if (!hidden) {
-            t.show(leash);
-        }
+        t.show(leash);
+        // TODO: change this back to use show instead of alpha when b/138459974 is fixed.
+        t.setAlpha(leash, hidden ? 0 : 1);
         t.reparent(surface, leash);
         return leash;
     }
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 0d18b30..f51d4c4 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -294,6 +294,10 @@
 
     private int getPreferredLaunchDisplay(@Nullable TaskRecord task,
             @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams) {
+        if (!mSupervisor.mService.mSupportsMultiDisplay) {
+            return DEFAULT_DISPLAY;
+        }
+
         int displayId = INVALID_DISPLAY;
         final int optionLaunchId = options != null ? options.getLaunchDisplayId() : INVALID_DISPLAY;
         if (optionLaunchId != INVALID_DISPLAY) {
@@ -321,6 +325,12 @@
             displayId = sourceDisplayId;
         }
 
+        if (displayId == INVALID_DISPLAY && options != null) {
+            final int callerDisplayId = options.getCallerDisplayId();
+            if (DEBUG) appendLog("display-from-caller=" + callerDisplayId);
+            displayId = callerDisplayId;
+        }
+
         if (displayId != INVALID_DISPLAY
                 && mSupervisor.mRootActivityContainer.getActivityDisplay(displayId) == null) {
             displayId = currentParams.mPreferredDisplayId;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fbdc54a..8fb23a4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2006,6 +2006,7 @@
 
             int attrChanges = 0;
             int flagChanges = 0;
+            int privateFlagChanges = 0;
             if (attrs != null) {
                 displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
                 // if they don't have the permission, mask out the status bar bits
@@ -2033,7 +2034,8 @@
                     attrs.height = win.mAttrs.height;
                 }
 
-                flagChanges = win.mAttrs.flags ^= attrs.flags;
+                flagChanges = win.mAttrs.flags ^ attrs.flags;
+                privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
                 attrChanges = win.mAttrs.copyFrom(attrs);
                 if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
                         | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
@@ -2050,7 +2052,7 @@
                             win.getDisplayContent().getDisplayId());
                 }
 
-                if ((flagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
+                if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
                     updateNonSystemOverlayWindowsVisibilityIfNeeded(
                             win, win.mWinAnimator.getShown());
                 }
@@ -7543,7 +7545,7 @@
             return;
         }
         final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
-        if (surfaceShown) {
+        if (surfaceShown && win.hideNonSystemOverlayWindowsWhenVisible()) {
             if (!mHidingNonSystemOverlayWindows.contains(win)) {
                 mHidingNonSystemOverlayWindows.add(win);
             }
@@ -7639,10 +7641,12 @@
             isDown = motionEvent.getAction() == MotionEvent.ACTION_DOWN;
             isUp = motionEvent.getAction() == MotionEvent.ACTION_UP;
         }
+        final boolean isMouseEvent = ev.getSource() == InputDevice.SOURCE_MOUSE;
 
         // For ACTION_DOWN, syncInputTransactions before injecting input.
+        // For all mouse events, also sync before injecting.
         // For ACTION_UP, sync after injecting.
-        if (isDown) {
+        if (isDown || isMouseEvent) {
             syncInputTransactions();
         }
         final boolean result =
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index f74e2c0..d7a519c 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -50,6 +50,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
+import android.os.Build;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -160,6 +161,8 @@
     // Thread currently set for VR scheduling
     int mVrThreadTid;
 
+    boolean mIsImeProcess;
+
     // all activities running in the process
     private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
     // any tasks this process had run root activities in
@@ -566,7 +569,8 @@
      * activities are allowed to be resumed per process.
      * @return {@code true} if the activity is allowed to be resumed by compatibility
      * restrictions, which the activity was the topmost visible activity in process or the app is
-     * targeting after Q.
+     * targeting after Q. Note that non-focusable activity, in picture-in-picture mode for instance,
+     * does not count as a topmost activity.
      */
     boolean updateTopResumingActivityInProcessIfNeeded(@NonNull ActivityRecord activity) {
         if (mInfo.targetSdkVersion >= Q || mPreQTopResumedActivity == activity) {
@@ -582,9 +586,13 @@
         boolean canUpdate = false;
         final ActivityDisplay topDisplay =
                 mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null;
-        // Update the topmost activity if current top activity was not on any display or no
-        // longer visible.
-        if (topDisplay == null || !mPreQTopResumedActivity.visible) {
+        // Update the topmost activity if current top activity is
+        // - not on any display OR
+        // - no longer visible OR
+        // - not focusable (in PiP mode for instance)
+        if (topDisplay == null
+                || !mPreQTopResumedActivity.visible
+                || !mPreQTopResumedActivity.isFocusable()) {
             canUpdate = true;
         }
 
@@ -949,17 +957,32 @@
         final Configuration config = getConfiguration();
         if (mLastReportedConfiguration.diff(config) == 0) {
             // Nothing changed.
+            if (Build.IS_DEBUGGABLE && mIsImeProcess) {
+                // TODO (b/135719017): Temporary log for debugging IME service.
+                Slog.w(TAG_CONFIGURATION, "Current config: " + config
+                        + " unchanged for IME proc " + mName);
+            }
             return;
         }
 
         try {
             if (mThread == null) {
+                if (Build.IS_DEBUGGABLE && mIsImeProcess) {
+                    // TODO (b/135719017): Temporary log for debugging IME service.
+                    Slog.w(TAG_CONFIGURATION, "Unable to send config for IME proc " + mName
+                            + ": no app thread");
+                }
                 return;
             }
             if (DEBUG_CONFIGURATION) {
                 Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName
                         + " new config " + config);
             }
+            if (Build.IS_DEBUGGABLE && mIsImeProcess) {
+                // TODO (b/135719017): Temporary log for debugging IME service.
+                Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName
+                        + " new config " + config);
+            }
             config.seq = mAtm.increaseConfigurationSeqLocked();
             mAtm.getLifecycleManager().scheduleTransaction(mThread,
                     ConfigurationChangeItem.obtain(config));
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 41840a4..ae3a10a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -329,9 +329,14 @@
             }
             mDrawState = COMMIT_DRAW_PENDING;
             layoutNeeded = true;
-        }
-        if (postDrawTransaction != null) {
-            mPostDrawTransaction.merge(postDrawTransaction);
+
+            if (postDrawTransaction != null) {
+                mPostDrawTransaction.merge(postDrawTransaction);
+            }
+        } else if (postDrawTransaction != null) {
+            // If draw state is not pending we may delay applying this transaction from the client,
+            // so apply it now.
+            postDrawTransaction.apply();
         }
 
         return layoutNeeded;
@@ -370,6 +375,13 @@
             // of the proper size. The preserved surface will still be removed when client
             // finishes drawing to the new surface.
             mSurfaceDestroyDeferred = false;
+
+            // Make sure to reparent any children of the new surface back to the preserved
+            // surface before destroying it.
+            if (mSurfaceController != null && mPendingDestroySurface != null) {
+                mPostDrawTransaction.reparentChildren(mSurfaceController.mSurfaceControl,
+                        mPendingDestroySurface.mSurfaceControl).apply();
+            }
             destroySurfaceLocked();
             mSurfaceDestroyDeferred = true;
             return;
@@ -1289,7 +1301,7 @@
         // if we are transparent.
         if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) {
             final SurfaceControl pendingSurfaceControl = mPendingDestroySurface.mSurfaceControl;
-            mPostDrawTransaction.hide(pendingSurfaceControl);
+            mPostDrawTransaction.reparent(pendingSurfaceControl, null);
             mPostDrawTransaction.reparentChildren(pendingSurfaceControl,
                     mSurfaceController.mSurfaceControl);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
index 85ca52e..279c678 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
@@ -31,11 +31,10 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.am.PersistentConnection;
 import com.android.server.appbinding.AppBindingUtils;
 
-import java.io.PrintWriter;
-
 /**
  * Manages connections to persistent services in owner packages.
  */
@@ -180,21 +179,24 @@
         }
     }
 
-    public void dump(String prefix, PrintWriter pw) {
+    /** dump content */
+    public void dump(IndentingPrintWriter pw) {
         synchronized (mLock) {
             if (mConnections.size() == 0) {
                 return;
             }
-            pw.println();
-            pw.print(prefix); pw.println("Owner Services:");
+            pw.println("Owner Services:");
+            pw.increaseIndent();
             for (int i = 0; i < mConnections.size(); i++) {
                 final int userId = mConnections.keyAt(i);
-                pw.print(prefix); pw.print("  "); pw.print("User: "); pw.println(userId);
+                pw.print("User: "); pw.println(userId);
 
                 final DevicePolicyServiceConnection con = mConnections.valueAt(i);
-                con.dump(prefix + "    ", pw);
+                pw.increaseIndent();
+                con.dump("", pw);
+                pw.decreaseIndent();
             }
-            pw.println();
+            pw.decreaseIndent();
         }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
index c50a5ff..f3a6935 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
@@ -22,8 +22,7 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
-
-import java.io.PrintWriter;
+import com.android.internal.util.IndentingPrintWriter;
 
 /**
  * Implementation of {@link DevicePolicyCache}, to which {@link DevicePolicyManagerService} pushes
@@ -80,9 +79,11 @@
     }
 
     /** Dump content */
-    public void dump(String prefix, PrintWriter pw) {
-        pw.println("Device policy cache");
-        pw.println(prefix + "Screen capture disabled: " + mScreenCaptureDisabled.toString());
-        pw.println(prefix + "Password quality: " + mPasswordQuality.toString());
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("Device policy cache:");
+        pw.increaseIndent();
+        pw.println("Screen capture disabled: " + mScreenCaptureDisabled.toString());
+        pw.println("Password quality: " + mPasswordQuality.toString());
+        pw.decreaseIndent();
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
index fd59b43..fec8a80 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
@@ -18,7 +18,8 @@
 import android.util.KeyValueListParser;
 import android.util.Slog;
 
-import java.io.PrintWriter;
+import com.android.internal.util.IndentingPrintWriter;
+
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -134,24 +135,22 @@
         return new DevicePolicyConstants(settings);
     }
 
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix);
+    /** Dump constants */
+    public void dump(IndentingPrintWriter pw) {
         pw.println("Constants:");
 
-        pw.print(prefix);
-        pw.print("  DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC: ");
+        pw.increaseIndent();
+        pw.print("DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC: ");
         pw.println(DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC);
 
-        pw.print(prefix);
-        pw.print("  DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE: ");
+        pw.print("DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE: ");
         pw.println(DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE);
 
-        pw.print(prefix);
-        pw.print("  DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC: ");
+        pw.print("DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC: ");
         pw.println(DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC);
 
-        pw.print(prefix);
-        pw.print("  DAS_DIED_SERVICE_STABLE_CONNECTION_THRESHOLD_SEC: ");
+        pw.print("DAS_DIED_SERVICE_STABLE_CONNECTION_THRESHOLD_SEC: ");
         pw.println(DAS_DIED_SERVICE_STABLE_CONNECTION_THRESHOLD_SEC);
+        pw.decreaseIndent();
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 68c9bad..ba06369 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -242,6 +242,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.StatLogger;
@@ -1667,111 +1668,115 @@
             info = deviceAdminInfo;
         }
 
-        void dump(String prefix, PrintWriter pw) {
-            pw.print(prefix); pw.print("uid="); pw.println(getUid());
-            pw.print(prefix); pw.print("testOnlyAdmin=");
+        void dump(IndentingPrintWriter pw) {
+            pw.print("uid="); pw.println(getUid());
+            pw.print("testOnlyAdmin=");
             pw.println(testOnlyAdmin);
-            pw.print(prefix); pw.println("policies:");
+            pw.println("policies:");
             ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
             if (pols != null) {
+                pw.increaseIndent();
                 for (int i=0; i<pols.size(); i++) {
-                    pw.print(prefix); pw.print("  "); pw.println(pols.get(i).tag);
+                    pw.println(pols.get(i).tag);
                 }
+                pw.decreaseIndent();
             }
-            pw.print(prefix); pw.print("passwordQuality=0x");
+            pw.print("passwordQuality=0x");
                     pw.println(Integer.toHexString(minimumPasswordMetrics.quality));
-            pw.print(prefix); pw.print("minimumPasswordLength=");
+            pw.print("minimumPasswordLength=");
                     pw.println(minimumPasswordMetrics.length);
-            pw.print(prefix); pw.print("passwordHistoryLength=");
+            pw.print("passwordHistoryLength=");
                     pw.println(passwordHistoryLength);
-            pw.print(prefix); pw.print("minimumPasswordUpperCase=");
+            pw.print("minimumPasswordUpperCase=");
                     pw.println(minimumPasswordMetrics.upperCase);
-            pw.print(prefix); pw.print("minimumPasswordLowerCase=");
+            pw.print("minimumPasswordLowerCase=");
                     pw.println(minimumPasswordMetrics.lowerCase);
-            pw.print(prefix); pw.print("minimumPasswordLetters=");
+            pw.print("minimumPasswordLetters=");
                     pw.println(minimumPasswordMetrics.letters);
-            pw.print(prefix); pw.print("minimumPasswordNumeric=");
+            pw.print("minimumPasswordNumeric=");
                     pw.println(minimumPasswordMetrics.numeric);
-            pw.print(prefix); pw.print("minimumPasswordSymbols=");
+            pw.print("minimumPasswordSymbols=");
                     pw.println(minimumPasswordMetrics.symbols);
-            pw.print(prefix); pw.print("minimumPasswordNonLetter=");
+            pw.print("minimumPasswordNonLetter=");
                     pw.println(minimumPasswordMetrics.nonLetter);
-            pw.print(prefix); pw.print("maximumTimeToUnlock=");
+            pw.print("maximumTimeToUnlock=");
                     pw.println(maximumTimeToUnlock);
-            pw.print(prefix); pw.print("strongAuthUnlockTimeout=");
+            pw.print("strongAuthUnlockTimeout=");
                     pw.println(strongAuthUnlockTimeout);
-            pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
+            pw.print("maximumFailedPasswordsForWipe=");
                     pw.println(maximumFailedPasswordsForWipe);
-            pw.print(prefix); pw.print("specifiesGlobalProxy=");
+            pw.print("specifiesGlobalProxy=");
                     pw.println(specifiesGlobalProxy);
-            pw.print(prefix); pw.print("passwordExpirationTimeout=");
+            pw.print("passwordExpirationTimeout=");
                     pw.println(passwordExpirationTimeout);
-            pw.print(prefix); pw.print("passwordExpirationDate=");
+            pw.print("passwordExpirationDate=");
                     pw.println(passwordExpirationDate);
             if (globalProxySpec != null) {
-                pw.print(prefix); pw.print("globalProxySpec=");
+                pw.print("globalProxySpec=");
                         pw.println(globalProxySpec);
             }
             if (globalProxyExclusionList != null) {
-                pw.print(prefix); pw.print("globalProxyEclusionList=");
+                pw.print("globalProxyEclusionList=");
                         pw.println(globalProxyExclusionList);
             }
-            pw.print(prefix); pw.print("encryptionRequested=");
+            pw.print("encryptionRequested=");
                     pw.println(encryptionRequested);
-            pw.print(prefix); pw.print("disableCamera=");
+            pw.print("disableCamera=");
                     pw.println(disableCamera);
-            pw.print(prefix); pw.print("disableCallerId=");
+            pw.print("disableCallerId=");
                     pw.println(disableCallerId);
-            pw.print(prefix); pw.print("disableContactsSearch=");
+            pw.print("disableContactsSearch=");
                     pw.println(disableContactsSearch);
-            pw.print(prefix); pw.print("disableBluetoothContactSharing=");
+            pw.print("disableBluetoothContactSharing=");
                     pw.println(disableBluetoothContactSharing);
-            pw.print(prefix); pw.print("disableScreenCapture=");
+            pw.print("disableScreenCapture=");
                     pw.println(disableScreenCapture);
-            pw.print(prefix); pw.print("requireAutoTime=");
+            pw.print("requireAutoTime=");
                     pw.println(requireAutoTime);
-            pw.print(prefix); pw.print("forceEphemeralUsers=");
+            pw.print("forceEphemeralUsers=");
                     pw.println(forceEphemeralUsers);
-            pw.print(prefix); pw.print("isNetworkLoggingEnabled=");
+            pw.print("isNetworkLoggingEnabled=");
                     pw.println(isNetworkLoggingEnabled);
-            pw.print(prefix); pw.print("disabledKeyguardFeatures=");
+            pw.print("disabledKeyguardFeatures=");
                     pw.println(disabledKeyguardFeatures);
-            pw.print(prefix); pw.print("crossProfileWidgetProviders=");
+            pw.print("crossProfileWidgetProviders=");
                     pw.println(crossProfileWidgetProviders);
             if (permittedAccessiblityServices != null) {
-                pw.print(prefix); pw.print("permittedAccessibilityServices=");
+                pw.print("permittedAccessibilityServices=");
                     pw.println(permittedAccessiblityServices);
             }
             if (permittedInputMethods != null) {
-                pw.print(prefix); pw.print("permittedInputMethods=");
+                pw.print("permittedInputMethods=");
                     pw.println(permittedInputMethods);
             }
             if (permittedNotificationListeners != null) {
-                pw.print(prefix); pw.print("permittedNotificationListeners=");
+                pw.print("permittedNotificationListeners=");
                 pw.println(permittedNotificationListeners);
             }
             if (keepUninstalledPackages != null) {
-                pw.print(prefix); pw.print("keepUninstalledPackages=");
+                pw.print("keepUninstalledPackages=");
                     pw.println(keepUninstalledPackages);
             }
-            pw.print(prefix); pw.print("organizationColor=");
+            pw.print("organizationColor=");
                     pw.println(organizationColor);
             if (organizationName != null) {
-                pw.print(prefix); pw.print("organizationName=");
+                pw.print("organizationName=");
                     pw.println(organizationName);
             }
-            pw.print(prefix); pw.println("userRestrictions:");
-            UserRestrictionsUtils.dumpRestrictions(pw, prefix + "  ", userRestrictions);
-            pw.print(prefix); pw.print("defaultEnabledRestrictionsAlreadySet=");
+            pw.println("userRestrictions:");
+            UserRestrictionsUtils.dumpRestrictions(pw, "  ", userRestrictions);
+            pw.print("defaultEnabledRestrictionsAlreadySet=");
                     pw.println(defaultEnabledRestrictionsAlreadySet);
-            pw.print(prefix); pw.print("isParent=");
+            pw.print("isParent=");
                     pw.println(isParent);
             if (parentAdmin != null) {
-                pw.print(prefix);  pw.println("parentAdmin:");
-                parentAdmin.dump(prefix + "  ", pw);
+                pw.println("parentAdmin:");
+                pw.increaseIndent();
+                parentAdmin.dump(pw);
+                pw.decreaseIndent();
             }
             if (mCrossProfileCalendarPackages != null) {
-                pw.print(prefix); pw.print("mCrossProfileCalendarPackages=");
+                pw.print("mCrossProfileCalendarPackages=");
                 pw.println(mCrossProfileCalendarPackages);
             }
         }
@@ -8843,46 +8848,62 @@
         }
     }
 
+    private void dumpDevicePolicyData(IndentingPrintWriter pw) {
+        int userCount = mUserData.size();
+        for (int u = 0; u < userCount; u++) {
+            DevicePolicyData policy = getUserData(mUserData.keyAt(u));
+            pw.println();
+            pw.println("Enabled Device Admins (User " + policy.mUserHandle
+                    + ", provisioningState: " + policy.mUserProvisioningState + "):");
+            final int n = policy.mAdminList.size();
+            for (int i = 0; i < n; i++) {
+                ActiveAdmin ap = policy.mAdminList.get(i);
+                if (ap != null) {
+                    pw.increaseIndent();
+                    pw.print(ap.info.getComponent().flattenToShortString());
+                    pw.println(":");
+                    pw.increaseIndent();
+                    ap.dump(pw);
+                    pw.decreaseIndent();
+                    pw.decreaseIndent();
+                }
+            }
+            if (!policy.mRemovingAdmins.isEmpty()) {
+                pw.increaseIndent();
+                pw.println("Removing Device Admins (User " + policy.mUserHandle + "): "
+                        + policy.mRemovingAdmins);
+                pw.decreaseIndent();
+            }
+            pw.println();
+            pw.increaseIndent();
+            pw.print("mPasswordOwner="); pw.println(policy.mPasswordOwner);
+            pw.decreaseIndent();
+        }
+    }
+
     @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
+    protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, printWriter)) return;
+        IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
 
         synchronized (getLockObject()) {
             pw.println("Current Device Policy Manager state:");
+            pw.increaseIndent();
 
-            mOwners.dump("  ", pw);
-            mDeviceAdminServiceController.dump("  ", pw);
-            int userCount = mUserData.size();
-            for (int u = 0; u < userCount; u++) {
-                DevicePolicyData policy = getUserData(mUserData.keyAt(u));
-                pw.println();
-                pw.println("  Enabled Device Admins (User " + policy.mUserHandle
-                        + ", provisioningState: " + policy.mUserProvisioningState + "):");
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin ap = policy.mAdminList.get(i);
-                    if (ap != null) {
-                        pw.print("    "); pw.print(ap.info.getComponent().flattenToShortString());
-                                pw.println(":");
-                        ap.dump("      ", pw);
-                    }
-                }
-                if (!policy.mRemovingAdmins.isEmpty()) {
-                    pw.println("    Removing Device Admins (User " + policy.mUserHandle + "): "
-                            + policy.mRemovingAdmins);
-                }
+            mOwners.dump(pw);
+            pw.println();
+            mDeviceAdminServiceController.dump(pw);
+            pw.println();
+            dumpDevicePolicyData(pw);
+            pw.println();
+            mConstants.dump(pw);
+            pw.println();
+            mStatLogger.dump(pw);
+            pw.println();
 
-                pw.println(" ");
-                pw.print("    mPasswordOwner="); pw.println(policy.mPasswordOwner);
-            }
+            pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
             pw.println();
-            mConstants.dump("  ", pw);
-            pw.println();
-            mStatLogger.dump(pw, "  ");
-            pw.println();
-            pw.println("  Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
-            pw.println();
-            mPolicyCache.dump("  ", pw);
+            mPolicyCache.dump(pw);
         }
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 215e46f..65bf86f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -41,6 +41,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
@@ -54,7 +55,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.util.List;
@@ -1032,27 +1032,29 @@
                     remoteBugreportHash, canAccessDeviceIds);
         }
 
-        public void dump(String prefix, PrintWriter pw) {
-            pw.println(prefix + "admin=" + admin);
-            pw.println(prefix + "name=" + name);
-            pw.println(prefix + "package=" + packageName);
-            pw.println(prefix + "canAccessDeviceIds=" + canAccessDeviceIds);
+        public void dump(IndentingPrintWriter pw) {
+            pw.println("admin=" + admin);
+            pw.println("name=" + name);
+            pw.println("package=" + packageName);
+            pw.println("canAccessDeviceIds=" + canAccessDeviceIds);
         }
     }
 
-    public void dump(String prefix, PrintWriter pw) {
+    public void dump(IndentingPrintWriter pw) {
         boolean needBlank = false;
         if (mDeviceOwner != null) {
-            pw.println(prefix + "Device Owner: ");
-            mDeviceOwner.dump(prefix + "  ", pw);
-            pw.println(prefix + "  User ID: " + mDeviceOwnerUserId);
+            pw.println("Device Owner: ");
+            pw.increaseIndent();
+            mDeviceOwner.dump(pw);
+            pw.println("User ID: " + mDeviceOwnerUserId);
+            pw.decreaseIndent();
             needBlank = true;
         }
         if (mSystemUpdatePolicy != null) {
             if (needBlank) {
                 pw.println();
             }
-            pw.println(prefix + "System Update Policy: " + mSystemUpdatePolicy);
+            pw.println("System Update Policy: " + mSystemUpdatePolicy);
             needBlank = true;
         }
         if (mProfileOwners != null) {
@@ -1060,8 +1062,10 @@
                 if (needBlank) {
                     pw.println();
                 }
-                pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): ");
-                entry.getValue().dump(prefix + "  ", pw);
+                pw.println("Profile Owner (User " + entry.getKey() + "): ");
+                pw.increaseIndent();
+                entry.getValue().dump(pw);
+                pw.decreaseIndent();
                 needBlank = true;
             }
         }
@@ -1069,14 +1073,14 @@
             if (needBlank) {
                 pw.println();
             }
-            pw.println(prefix + "Pending System Update: " + mSystemUpdateInfo);
+            pw.println("Pending System Update: " + mSystemUpdateInfo);
             needBlank = true;
         }
         if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) {
             if (needBlank) {
                 pw.println();
             }
-            pw.println(prefix + "System update freeze record: "
+            pw.println("System update freeze record: "
                     + getSystemUpdateFreezePeriodRecordAsString());
             needBlank = true;
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9fe44dc..6e0d834 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -67,7 +67,6 @@
 import android.util.Slog;
 import android.view.WindowManager;
 import android.view.contentcapture.ContentCaptureManager;
-import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
@@ -101,8 +100,8 @@
 import com.android.server.incident.IncidentCompanionService;
 import com.android.server.input.InputManagerService;
 import com.android.server.inputmethod.InputMethodManagerService;
+import com.android.server.inputmethod.InputMethodSystemProperty;
 import com.android.server.inputmethod.MultiClientInputMethodManagerService;
-import com.android.server.job.JobSchedulerService;
 import com.android.server.lights.LightsService;
 import com.android.server.media.MediaResourceMonitorService;
 import com.android.server.media.MediaRouterService;
@@ -1575,8 +1574,9 @@
             mSystemServiceManager.startService(ColorDisplayService.class);
             t.traceEnd();
 
+            // TODO(aml-jobscheduler): Think about how to do it properly.
             t.traceBegin("StartJobScheduler");
-            mSystemServiceManager.startService(JobSchedulerService.class);
+            mSystemServiceManager.startService(JOB_SCHEDULER_SERVICE_CLASS);
             t.traceEnd();
 
             t.traceBegin("StartSoundTrigger");
@@ -1980,6 +1980,11 @@
         }
         t.traceEnd();
 
+        // Permission policy service
+        t.traceBegin("StartPermissionPolicyService");
+        mSystemServiceManager.startService(PermissionPolicyService.class);
+        t.traceEnd();
+
         t.traceBegin("MakePackageManagerServiceReady");
         mPackageManagerService.systemReady();
         t.traceEnd();
@@ -2014,11 +2019,6 @@
         mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
         t.traceEnd();
 
-        // Permission policy service
-        t.traceBegin("StartPermissionPolicyService");
-        mSystemServiceManager.startService(PermissionPolicyService.class);
-        t.traceEnd();
-
         // These are needed to propagate to the runnable below.
         final NetworkManagementService networkManagementF = networkManagement;
         final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 2baa4d8..ad94e61 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -20,6 +20,7 @@
     static_libs: [
         "services.core",
         "services.net",
+        "jobscheduler-service",
         "androidx.test.runner",
         "mockito-target-extended-minus-junit4",
         "platform-test-annotations",
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
index 4a33739..101bee2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
@@ -21,12 +21,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Process;
 import android.platform.test.annotations.Presubmit;
 import android.provider.DeviceConfig;
 import android.text.TextUtils;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.ServiceThread;
 import com.android.server.appop.AppOpsService;
 import com.android.server.testables.TestableDeviceConfig;
 
@@ -54,6 +59,8 @@
 @RunWith(MockitoJUnitRunner.class)
 public final class AppCompactorTest {
 
+    private ServiceThread mThread;
+
     @Mock
     private AppOpsService mAppOpsService;
     private AppCompactor mCompactorUnderTest;
@@ -70,7 +77,12 @@
         mHandlerThread = new HandlerThread("");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
-        ActivityManagerService ams = new ActivityManagerService(new TestInjector());
+
+        mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT,
+                true /* allowIo */);
+        mThread.start();
+
+        ActivityManagerService ams = new ActivityManagerService(new TestInjector(), mThread);
         mCompactorUnderTest = new AppCompactor(ams,
                 new AppCompactor.PropertyChangedCallbackForTest() {
                     @Override
@@ -85,6 +97,7 @@
     @After
     public void tearDown() {
         mHandlerThread.quit();
+        mThread.quit();
         mCountDown = null;
     }
 
@@ -656,5 +669,10 @@
         public Handler getUiHandler(ActivityManagerService service) {
             return mHandler;
         }
+
+        @Override
+        public Context getContext() {
+            return InstrumentationRegistry.getInstrumentation().getContext();
+        }
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 328e8f4..1c88c40 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -400,22 +400,7 @@
     }
 
     @Test
-    public void testEvaluateStateLocked_HeartbeatsOn() {
-        mConstants.USE_HEARTBEATS = true;
-        final ConnectivityController controller = new ConnectivityController(mService);
-        final JobStatus red = createJobStatus(createJob()
-                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
-                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED), UID_RED);
-
-        controller.evaluateStateLocked(red);
-        assertFalse(controller.isStandbyExceptionRequestedLocked(UID_RED));
-        verify(mNetPolicyManagerInternal, never())
-                .setAppIdleWhitelist(eq(UID_RED), anyBoolean());
-    }
-
-    @Test
     public void testEvaluateStateLocked_JobWithoutConnectivity() {
-        mConstants.USE_HEARTBEATS = false;
         final ConnectivityController controller = new ConnectivityController(mService);
         final JobStatus red = createJobStatus(createJob().setMinimumLatency(1));
 
@@ -427,7 +412,6 @@
 
     @Test
     public void testEvaluateStateLocked_JobWouldBeReady() {
-        mConstants.USE_HEARTBEATS = false;
         final ConnectivityController controller = spy(new ConnectivityController(mService));
         doReturn(true).when(controller).wouldBeReadyWithConnectivityLocked(any());
         final JobStatus red = createJobStatus(createJob()
@@ -466,7 +450,6 @@
 
     @Test
     public void testEvaluateStateLocked_JobWouldNotBeReady() {
-        mConstants.USE_HEARTBEATS = false;
         final ConnectivityController controller = spy(new ConnectivityController(mService));
         doReturn(false).when(controller).wouldBeReadyWithConnectivityLocked(any());
         final JobStatus red = createJobStatus(createJob()
@@ -502,7 +485,6 @@
 
     @Test
     public void testReevaluateStateLocked() {
-        mConstants.USE_HEARTBEATS = false;
         final ConnectivityController controller = spy(new ConnectivityController(mService));
         final JobStatus redOne = createJobStatus(createJob(1)
                 .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
@@ -625,7 +607,7 @@
 
     private static JobStatus createJobStatus(JobInfo.Builder job, int uid,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
-        return new JobStatus(job.build(), uid, null, -1, 0, 0, null,
+        return new JobStatus(job.build(), uid, null, -1, 0, null,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0);
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 94e02d3..64da6f6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -573,7 +573,7 @@
             long latestRunTimeElapsedMillis) {
         final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
-        return new JobStatus(job, 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis,
+        return new JobStatus(job, 0, null, -1, 0, null, earliestRunTimeElapsedMillis,
                 latestRunTimeElapsedMillis, 0, 0, null, 0);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 2d70231..8863d5a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -107,7 +107,6 @@
     private static final int SOURCE_USER_ID = 0;
 
     private BroadcastReceiver mChargingReceiver;
-    private Constants mJsConstants;
     private QuotaController mQuotaController;
     private QuotaController.QcConstants mQcConstants;
     private int mSourceUid;
@@ -134,14 +133,11 @@
                 .strictness(Strictness.LENIENT)
                 .mockStatic(LocalServices.class)
                 .startMocking();
-        // Make sure constants turn on QuotaController.
-        mJsConstants = new Constants();
-        mJsConstants.USE_HEARTBEATS = false;
 
         // Called in StateController constructor.
         when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
         when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
-        when(mJobSchedulerService.getConstants()).thenReturn(mJsConstants);
+        when(mJobSchedulerService.getConstants()).thenReturn(mock(Constants.class));
         // Called in QuotaController constructor.
         IActivityManager activityManager = ActivityManager.getService();
         spyOn(activityManager);
@@ -1809,30 +1805,6 @@
                 .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
     }
 
-    /** Tests that QuotaController doesn't throttle if throttling is turned off. */
-    @Test
-    public void testThrottleToggling() throws Exception {
-        setDischarging();
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(
-                        JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
-                        10 * MINUTE_IN_MILLIS, 4));
-        JobStatus jobStatus = createJobStatus("testThrottleToggling", 1);
-        setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window
-        mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
-        assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
-
-        mJsConstants.USE_HEARTBEATS = true;
-        mQuotaController.onConstantsUpdatedLocked();
-        Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background.
-        assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
-
-        mJsConstants.USE_HEARTBEATS = false;
-        mQuotaController.onConstantsUpdatedLocked();
-        Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background.
-        assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
-    }
-
     @Test
     public void testConstantsUpdating_ValidValues() {
         mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 0614b3a..b37e460 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -40,6 +40,7 @@
         "hamcrest-library",
         "servicestests-utils",
         "xml-writer-device-lib",
+        "jobscheduler-service",
     ],
 
     aidl: {
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 01f2f6b..c1bbb30 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -69,6 +69,7 @@
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.HARDWARE_TEST"/>
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index a4267b8..1084d62 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -179,9 +179,9 @@
         addA11yWindowInfo(mA11yWindowInfos, WINDOWID, false);
         addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true);
         when(mMockA11yWindowManager.getWindowListLocked()).thenReturn(mA11yWindowInfos);
-        when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID))
+        when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID))
                 .thenReturn(mA11yWindowInfos.get(0));
-        when(mMockA11yWindowManager.findA11yWindowInfoById(PIP_WINDOWID))
+        when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(PIP_WINDOWID))
                 .thenReturn(mA11yWindowInfos.get(1));
         final RemoteAccessibilityConnection conn = getRemoteA11yConnection(
                 WINDOWID, mMockIA11yInteractionConnection, PACKAGE_NAME1);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
index 782dc3e..193f540 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
@@ -47,6 +47,8 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.accessibility.gestures.TouchExplorer;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
index bb35776..04ac7fe 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -166,7 +166,7 @@
     public void canDispatchAccessibilityEvent_otherEvents_windowIdExist_returnTrue() {
         when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM))
                 .thenReturn(WINDOWID2);
-        when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID))
+        when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID))
                 .thenReturn(AccessibilityWindowInfo.obtain());
         for (int i = 0; i < OTHER_EVENTS.length; i++) {
             final AccessibilityEvent event = AccessibilityEvent.obtain(OTHER_EVENTS[i]);
@@ -287,7 +287,7 @@
                 .thenReturn(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
         when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM))
                 .thenReturn(WINDOWID2);
-        when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID))
+        when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID))
                 .thenReturn(AccessibilityWindowInfo.obtain());
 
         assertTrue(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(UserHandle.USER_SYSTEM,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 2f9f9bb..6be5a37 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -192,7 +192,8 @@
         when(parceledListSlice.getList()).thenReturn(gestureSteps);
         mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
 
-        verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0);
+        verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0,
+                Display.DEFAULT_DISPLAY);
     }
 
     @Test
@@ -209,7 +210,8 @@
         when(parceledListSlice.getList()).thenReturn(gestureSteps);
         mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
 
-        verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0);
+        verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0,
+                Display.DEFAULT_DISPLAY);
         verify(mMockServiceClient).onPerformGestureResult(0, false);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 7e64caf..7887d5b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -34,6 +34,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -53,6 +54,7 @@
 
 import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
 
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
@@ -75,9 +77,12 @@
     private static final boolean FORCE_SEND = true;
     private static final boolean SEND_ON_WINDOW_CHANGES = false;
     private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
+    // TO-DO [Multi-Display] : change the display count to 2
+    private static final int DISPLAY_COUNT = 1;
     private static final int NUM_GLOBAL_WINDOWS = 4;
     private static final int NUM_APP_WINDOWS = 4;
-    private static final int NUM_OF_WINDOWS = NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS;
+    private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS)
+            * DISPLAY_COUNT;
     private static final int DEFAULT_FOCUSED_INDEX = 1;
     private static final int SCREEN_WIDTH = 1080;
     private static final int SCREEN_HEIGHT = 1920;
@@ -86,7 +91,13 @@
 
     // List of window token, mapping from windowId -> window token.
     private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
-    private final ArrayList<WindowInfo> mWindowInfos = new ArrayList<>();
+    // List of window info lists, mapping from displayId -> window info lists.
+    private final SparseArray<ArrayList<WindowInfo>> mWindowInfos =
+            new SparseArray<>();
+    // List of callback, mapping from displayId -> callback.
+    private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
+            new SparseArray<>();
+
     private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
 
     @Mock private WindowManagerInternal mMockWindowManagerInternal;
@@ -109,29 +120,14 @@
                 mMockA11ySecurityPolicy,
                 mMockA11yUserManager);
 
-        // Add RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
-        // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
-        // for the test.
-        int layer = 0;
-        for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
-            final IWindow token = addAccessibilityInteractionConnection(true);
-            addWindowInfo(token, layer++);
-
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            when(mMockWindowManagerInternal.setWindowsForAccessibilityCallback(eq(i), any()))
+                    .thenReturn(true);
+            startTrackingPerDisplay(i);
         }
-        for (int i = 0; i < NUM_APP_WINDOWS; i++) {
-            final IWindow token = addAccessibilityInteractionConnection(false);
-            addWindowInfo(token, layer++);
-        }
-        // setup default focus
-        mWindowInfos.get(DEFAULT_FOCUSED_INDEX).focused = true;
-        // Turn on windows tracking, and update window info
-        mA11yWindowManager.startTrackingWindows();
-        mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
-        assertEquals(mA11yWindowManager.getWindowListLocked().size(),
-                mWindowInfos.size());
 
         // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged.
-        // Reset it for mockito verify of further test case.
+        // Resets it for mockito verify of further test case.
         Mockito.reset(mMockA11yEventSender);
     }
 
@@ -142,11 +138,12 @@
 
     @Test
     public void startTrackingWindows_shouldEnableWindowManagerCallback() {
-        // AccessibilityWindowManager#startTrackingWindows already invoked in setup
+        // AccessibilityWindowManager#startTrackingWindows already invoked in setup.
         assertTrue(mA11yWindowManager.isTrackingWindowsLocked());
-        // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
+        final WindowsForAccessibilityCallback callbacks =
+                mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
         verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
-                eq(Display.DEFAULT_DISPLAY), any());
+                eq(Display.DEFAULT_DISPLAY), eq(callbacks));
     }
 
     @Test
@@ -156,9 +153,9 @@
 
         mA11yWindowManager.stopTrackingWindows();
         assertFalse(mA11yWindowManager.isTrackingWindowsLocked());
-        // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
         verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
-                eq(Display.DEFAULT_DISPLAY), any());
+                eq(Display.DEFAULT_DISPLAY), isNull());
+
     }
 
     @Test
@@ -177,87 +174,102 @@
     @Test
     public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
         final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
+        WindowInfo focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
         assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, focusedWindowInfo.token));
 
         focusedWindowInfo.focused = false;
-        focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1);
+        focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1);
         focusedWindowInfo.focused = true;
 
         mA11yWindowManager.onTouchInteractionStart();
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+        setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
         assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
     }
 
     @Test
     public void onWindowsChanged_shouldReportCorrectLayer() {
-        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup
-        List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
+        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked();
         for (int i = 0; i < a11yWindows.size(); i++) {
             final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
-            final WindowInfo windowInfo = mWindowInfos.get(i);
-            assertThat(mWindowInfos.size() - windowInfo.layer - 1,
+            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
+            assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1,
                     is(a11yWindow.getLayer()));
         }
     }
 
     @Test
     public void onWindowsChanged_shouldReportCorrectOrder() {
-        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup
-        List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
+        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked();
         for (int i = 0; i < a11yWindows.size(); i++) {
             final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
             final IBinder windowToken = mA11yWindowManager
                     .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
-            final WindowInfo windowInfo = mWindowInfos.get(i);
+            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
             assertThat(windowToken, is(windowInfo.token));
         }
     }
 
     @Test
     public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
-        final WindowInfo windowInfo = mWindowInfos.get(0);
-        final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        final int correctLayer =
+                mA11yWindowManager.getWindowListLocked().get(0).getLayer();
         windowInfo.layer += 1;
 
-        mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
-        assertNotEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        assertNotEquals(correctLayer,
+                mA11yWindowManager.getWindowListLocked().get(0).getLayer());
     }
 
     @Test
     public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
-        final WindowInfo windowInfo = mWindowInfos.get(0);
-        final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        final int correctLayer =
+                mA11yWindowManager.getWindowListLocked().get(0).getLayer();
         windowInfo.layer += 1;
 
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
-        assertEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertEquals(correctLayer,
+                mA11yWindowManager.getWindowListLocked().get(0).getLayer());
     }
 
     @Test
     public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
             throws RemoteException {
-        final AccessibilityWindowInfo oldWindow = mA11yWindowManager.getWindowListLocked().get(0);
-        final IWindow token = addAccessibilityInteractionConnection(true);
+        final AccessibilityWindowInfo oldWindow =
+                mA11yWindowManager.getWindowListLocked().get(0);
+        final IWindow token =
+                addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, true);
         final WindowInfo windowInfo = WindowInfo.obtain();
         windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
         windowInfo.token = token.asBinder();
         windowInfo.layer = 0;
         windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-        mWindowInfos.set(0, windowInfo);
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo);
 
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
-        assertNotEquals(oldWindow, mA11yWindowManager.getWindowListLocked().get(0));
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertNotEquals(oldWindow,
+                mA11yWindowManager.getWindowListLocked().get(0));
     }
 
     @Test
     public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
-        final WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
-        final WindowInfo windowInfo = mWindowInfos.get(0);
+        final WindowInfo focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
         focusedWindowInfo.focused = false;
         windowInfo.focused = true;
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
         assertTrue(mA11yWindowManager.getWindowListLocked().get(0).isFocused());
     }
 
@@ -288,7 +300,8 @@
 
     @Test
     public void getWindowTokenForUserAndWindowId_shouldNotNull() {
-        final List<AccessibilityWindowInfo> windows = mA11yWindowManager.getWindowListLocked();
+        final List<AccessibilityWindowInfo> windows =
+                mA11yWindowManager.getWindowListLocked();
         for (int i = 0; i < windows.size(); i++) {
             final int windowId = windows.get(i).getId();
 
@@ -299,7 +312,8 @@
 
     @Test
     public void findWindowId() {
-        final List<AccessibilityWindowInfo> windows = mA11yWindowManager.getWindowListLocked();
+        final List<AccessibilityWindowInfo> windows =
+                mA11yWindowManager.getWindowListLocked();
         for (int i = 0; i < windows.size(); i++) {
             final int windowId = windows.get(i).getId();
             final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
@@ -313,13 +327,15 @@
     @Test
     public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
         // Updates top 2 z-order WindowInfo are whole visible.
-        WindowInfo windowInfo = mWindowInfos.get(0);
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
         windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
-        windowInfo = mWindowInfos.get(1);
-        windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT);
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+        windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1);
+        windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2,
+                SCREEN_WIDTH, SCREEN_HEIGHT);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
-        final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked();
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(0).getId();
 
@@ -336,12 +352,13 @@
 
     @Test
     public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
-        // Updates z-order #1 WindowInfo is half visible
-        WindowInfo windowInfo = mWindowInfos.get(0);
+        // Updates z-order #1 WindowInfo is half visible.
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
         windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
 
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
-        final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked();
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
@@ -353,7 +370,8 @@
     @Test
     public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
         // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
-        final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked();
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
@@ -366,11 +384,12 @@
         // Updates z-order #0 WindowInfo to have two interact-able areas.
         Region region = new Region(0, 0, SCREEN_WIDTH, 200);
         region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
-        WindowInfo windowInfo = mWindowInfos.get(0);
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
         windowInfo.regionInScreen.set(region);
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
-        final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked();
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
@@ -382,7 +401,8 @@
 
     @Test
     public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
-        final IBinder eventWindowToken = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1).token;
+        final IBinder eventWindowToken =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token;
         final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, eventWindowToken);
         when(mMockWindowManagerInternal.getFocusedWindowToken())
@@ -402,7 +422,8 @@
 
     @Test
     public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() {
-        final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1);
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
         final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
         assertThat(currentActiveWindowId, is(not(eventWindowId)));
 
@@ -428,7 +449,8 @@
 
     @Test
     public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() {
-        final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX);
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX);
         final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
                 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
         assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
@@ -457,7 +479,8 @@
 
     @Test
     public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() {
-        final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX);
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX);
         final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
                 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
         assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
@@ -482,7 +505,8 @@
 
     @Test
     public void onTouchInteractionEnd_shouldRollbackActiveWindow() {
-        final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1);
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
         final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
         assertThat(currentActiveWindowId, is(not(eventWindowId)));
 
@@ -513,12 +537,14 @@
     @Test
     public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
             throws RemoteException {
-        final IBinder defaultFocusWinToken = mWindowInfos.get(DEFAULT_FOCUSED_INDEX).token;
+        final IBinder defaultFocusWinToken =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token;
         final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, defaultFocusWinToken);
         when(mMockWindowManagerInternal.getFocusedWindowToken())
                 .thenReturn(defaultFocusWinToken);
-        final int newFocusWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1);
+        final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
         final IAccessibilityInteractionConnection mockNewFocusConnection =
                 mA11yWindowManager.getConnectionLocked(
                         USER_SYSTEM_ID, newFocusWindowId).getRemote();
@@ -556,28 +582,72 @@
 
     @Test
     public void getPictureInPictureWindow_shouldNotNull() {
-        assertNull(mA11yWindowManager.getPictureInPictureWindow());
-        mWindowInfos.get(1).inPictureInPicture = true;
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+        assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true;
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
-        assertNotNull(mA11yWindowManager.getPictureInPictureWindow());
+        assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
     }
 
     @Test
     public void notifyOutsideTouch() throws RemoteException {
-        final int targetWindowId = getWindowIdFromWindowInfos(1);
-        final int outsideWindowId = getWindowIdFromWindowInfos(0);
+        final int targetWindowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1);
+        final int outsideWindowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
         final IAccessibilityInteractionConnection mockRemoteConnection =
                 mA11yWindowManager.getConnectionLocked(
                         USER_SYSTEM_ID, outsideWindowId).getRemote();
-        mWindowInfos.get(0).hasFlagWatchOutsideTouch = true;
-        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true;
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
         verify(mockRemoteConnection).notifyOutsideTouch();
     }
 
-    private IWindow addAccessibilityInteractionConnection(boolean bGlobal)
+    private void startTrackingPerDisplay(int displayId) throws RemoteException {
+        ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
+        // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
+        // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
+        // for the test.
+        int layer = 0;
+        for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
+            final IWindow token = addAccessibilityInteractionConnection(displayId, true);
+            addWindowInfo(windowInfosForDisplay, token, layer++);
+
+        }
+        for (int i = 0; i < NUM_APP_WINDOWS; i++) {
+            final IWindow token = addAccessibilityInteractionConnection(displayId, false);
+            addWindowInfo(windowInfosForDisplay, token, layer++);
+        }
+        // Setups default focus.
+        windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
+        // Turns on windows tracking, and update window info.
+        mA11yWindowManager.startTrackingWindows();
+        // Puts window lists into array.
+        mWindowInfos.put(displayId, windowInfosForDisplay);
+        // Sets the default display as the top focused display.
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
+        }
+        // Invokes callback for sending window lists to A11y framework.
+        onWindowsForAccessibilityChanged(displayId, FORCE_SEND);
+
+        assertEquals(mA11yWindowManager.getWindowListLocked().size(),
+                windowInfosForDisplay.size());
+    }
+
+    private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
+        ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
+                ArgumentCaptor.forClass(
+                        WindowManagerInternal.WindowsForAccessibilityCallback.class);
+        verify(mMockWindowManagerInternal)
+                .setWindowsForAccessibilityCallback(eq(displayId),
+                        windowsForAccessibilityCallbacksCaptor.capture());
+        return windowsForAccessibilityCallbacksCaptor.getValue();
+    }
+
+    private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal)
             throws RemoteException {
         final IWindow mockWindowToken = Mockito.mock(IWindow.class);
         final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
@@ -588,6 +658,8 @@
         when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
         when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(USER_SYSTEM_ID))
                 .thenReturn(bGlobal);
+        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowToken.asBinder()))
+                .thenReturn(displayId);
 
         int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
                 mockWindowToken, mockA11yConnection, PACKAGE_NAME, USER_SYSTEM_ID);
@@ -595,21 +667,40 @@
         return mockWindowToken;
     }
 
-    private void addWindowInfo(IWindow windowToken, int layer) {
+    private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) {
         final WindowInfo windowInfo = WindowInfo.obtain();
         windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
         windowInfo.token = windowToken.asBinder();
         windowInfo.layer = layer;
         windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-        mWindowInfos.add(windowInfo);
+        windowInfos.add(windowInfo);
     }
 
-    private int getWindowIdFromWindowInfos(int index) {
-        final IBinder windowToken = mWindowInfos.get(index).token;
+    private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
+        final IBinder windowToken = mWindowInfos.get(displayId).get(index).token;
         return mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, windowToken);
     }
 
+    private void setTopFocusedWindowAndDisplay(int displayId, int index) {
+        // Sets the top focus window.
+        final IBinder eventWindowToken = mWindowInfos.get(displayId).get(index).token;
+        when(mMockWindowManagerInternal.getFocusedWindowToken())
+                .thenReturn(eventWindowToken);
+        // Sets the top focused display.
+        when(mMockWindowManagerInternal.getDisplayIdForWindow(eventWindowToken))
+                .thenReturn(displayId);
+    }
+
+    private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) {
+        WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
+        if (callbacks == null) {
+            callbacks = getWindowsForAccessibilityCallbacks(displayId);
+            mCallbackOfWindows.put(displayId, callbacks);
+        }
+        callbacks.onWindowsForAccessibilityChanged(forceSend, mWindowInfos.get(displayId));
+    }
+
     static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
         private int mWindowId;
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index 2977414..f1142fd 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -47,6 +47,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.Display;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -709,7 +710,8 @@
 
     private void injectEventsSync(List<GestureStep> gestureSteps,
             IAccessibilityServiceClient serviceInterface, int sequence) {
-        mMotionEventInjector.injectEvents(gestureSteps, serviceInterface, sequence);
+        mMotionEventInjector.injectEvents(gestureSteps, serviceInterface, sequence,
+                Display.DEFAULT_DISPLAY);
         // Dispatch the message sent by the injector. Our simple handler doesn't guarantee stuff
         // happens in order.
         mMessageCapturingHandler.sendLastMessage();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
rename to services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java
index cdcc338..2585a28 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.accessibility;
+package com.android.server.accessibility.gestures;
 
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.mock;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java
rename to services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 2645461..274ca36 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.accessibility;
+package com.android.server.accessibility.gestures;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -31,6 +31,9 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accessibility.EventStreamTransformation;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index 5dafe07..d57fd4b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -18,13 +18,17 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
 
 import android.app.ActivityManagerInternal;
 import android.os.SystemClock;
 
 import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -43,6 +47,8 @@
     private static final long TEST_PROC_STATE_SEQ2 = 1112;
     private static final long TEST_PROC_STATE_SEQ3 = 1113;
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     @Mock private ActivityManagerService.Injector mMockInjector;
 
     private ActivityManagerService mAms;
@@ -52,7 +58,11 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mAms = new ActivityManagerService(mMockInjector);
+        doReturn(InstrumentationRegistry.getInstrumentation().getContext()).when(mMockInjector)
+                .getContext();
+        doReturn(mServiceThreadRule.getThread().getThreadHandler()).when(mMockInjector)
+                .getUiHandler(any());
+        mAms = new ActivityManagerService(mMockInjector, mServiceThreadRule.getThread());
         mAmi = mAms.new LocalService();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 3df6976..8a1f046 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -70,13 +70,14 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.appop.AppOpsService;
 import com.android.server.am.ProcessList.IsolatedUidRange;
 import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
+import com.android.server.appop.AppOpsService;
 import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -114,6 +115,8 @@
         UidRecord.CHANGE_ACTIVE
     };
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private Context mContext = getInstrumentation().getTargetContext();
     @Mock private AppOpsService mAppOpsService;
     @Mock private PackageManager mPackageManager;
@@ -131,7 +134,7 @@
         mHandlerThread.start();
         mHandler = new TestHandler(mHandlerThread.getLooper());
         mInjector = new TestInjector();
-        mAms = new ActivityManagerService(mInjector);
+        mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread());
         mAms.mWaitForNetworkTimeoutMs = 2000;
         mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
         mAms.mActivityTaskManager.initialize(null, null, mHandler.getLooper());
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 1dfce51..87cc0ff 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -29,6 +29,7 @@
 import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.io.File;
@@ -41,6 +42,9 @@
 @FlakyTest(bugId = 113616538)
 public class AppErrorDialogTest {
 
+    @Rule
+    public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private Context mContext;
     private ActivityManagerService mService;
 
@@ -55,14 +59,19 @@
 
             @Override
             public Handler getUiHandler(ActivityManagerService service) {
-                return null;
+                return mServiceThreadRule.getThread().getThreadHandler();
             }
 
             @Override
             public boolean isNetworkRestrictedForUid(int uid) {
                 return false;
             }
-        });
+
+            @Override
+            public Context getContext() {
+                return mContext;
+            }
+        }, mServiceThreadRule.getThread());
         mService.mActivityTaskManager = new ActivityTaskManagerService(mContext);
         mService.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
     }
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
index cbdc6c3..1eb02ad 100644
--- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -39,6 +39,7 @@
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -61,6 +62,8 @@
     private static final float TEST_FLOAT = 3.14f;
     private static final String TEST_STRING = "testString";
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private ActivityManagerService mAms;
     @Mock private Context mContext;
 
@@ -90,7 +93,7 @@
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
 
-        mAms = new ActivityManagerService(new TestInjector());
+        mAms = new ActivityManagerService(new TestInjector(), mServiceThreadRule.getThread());
         mCoreSettingsObserver = new CoreSettingsObserver(mAms);
     }
 
@@ -157,7 +160,7 @@
     private class TestInjector extends Injector {
         @Override
         public Context getContext() {
-            return mContext;
+            return getInstrumentation().getContext();
         }
 
         @Override
@@ -167,7 +170,7 @@
 
         @Override
         public Handler getUiHandler(ActivityManagerService service) {
-            return null;
+            return mServiceThreadRule.getThread().getThreadHandler();
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java b/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java
new file mode 100644
index 0000000..e86ce7e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.os.Process;
+
+import com.android.server.ServiceThread;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+class ServiceThreadRule implements TestRule {
+
+    private ServiceThread mThread;
+
+    ServiceThread getThread() {
+        return mThread;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT,
+                        true /* allowIo */);
+                mThread.start();
+                try {
+                    base.evaluate();
+                } finally {
+                    mThread.getThreadHandler().runWithScissors(mThread::quit, 0 /* timeout */);
+                }
+            }
+        };
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
new file mode 100644
index 0000000..5c2ad94
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.audio;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+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 static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AudioDeviceBrokerTest {
+
+    private static final String TAG = "AudioDeviceBrokerTest";
+    private static final int MAX_MESSAGE_HANDLING_DELAY_MS = 100;
+
+    private Context mContext;
+    // the actual class under test
+    private AudioDeviceBroker mAudioDeviceBroker;
+
+    @Mock private AudioService mMockAudioService;
+    @Spy private AudioDeviceInventory mSpyDevInventory;
+
+    private BluetoothDevice mFakeBtDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+
+        mMockAudioService = mock(AudioService.class);
+        mSpyDevInventory = spy(new AudioDeviceInventory());
+        mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory);
+        mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker);
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mFakeBtDevice = adapter.getRemoteDevice("00:01:02:03:04:05");
+        Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
+    }
+
+    @After
+    public void tearDown() throws Exception { }
+
+    @Test
+    public void testSetUpAndTearDown() { }
+
+    /**
+     * Verify call to postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent() for connection
+     * calls into AudioDeviceInventory with the right params
+     * @throws Exception
+     */
+    @Test
+    public void testPostA2dpDeviceConnectionChange() throws Exception {
+        Log.i(TAG, "testPostA2dpDeviceConnectionChange");
+        Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
+
+        mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1);
+        Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
+        verify(mSpyDevInventory, times(1)).setBluetoothA2dpDeviceConnectionState(
+                any(BluetoothDevice.class),
+                ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED) /*state*/,
+                ArgumentMatchers.eq(BluetoothProfile.A2DP) /*profile*/,
+                ArgumentMatchers.eq(true) /*suppressNoisyIntent*/, anyInt() /*musicDevice*/,
+                ArgumentMatchers.eq(1) /*a2dpVolume*/
+        );
+    }
+
+    /**
+     * Verify call to postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent() for
+     *    connection > pause > disconnection > connection
+     * keeps the device connected
+     * @throws Exception
+     */
+    @Test
+    public void testA2dpDeviceConnectionDisconnectionConnectionChange() throws Exception {
+        Log.i(TAG, "testA2dpDeviceConnectionDisconnectionConnectionChange");
+
+        doTestConnectionDisconnectionReconnection(0);
+    }
+
+    /**
+     * Verify device disconnection and reconnection within the BECOMING_NOISY window
+     * @throws Exception
+     */
+    @Test
+    public void testA2dpDeviceReconnectionWithinBecomingNoisyDelay() throws Exception {
+        Log.i(TAG, "testA2dpDeviceReconnectionWithinBecomingNoisyDelay");
+
+        doTestConnectionDisconnectionReconnection(AudioService.BECOMING_NOISY_DELAY_MS / 2);
+    }
+
+    private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection)
+            throws Exception {
+        when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC))
+                .thenReturn(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+        when(mMockAudioService.isInCommunication()).thenReturn(false);
+        when(mMockAudioService.hasMediaDynamicPolicy()).thenReturn(false);
+        when(mMockAudioService.hasAudioFocusUsers()).thenReturn(false);
+
+        // first connection
+        mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1);
+        Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
+
+        // disconnection
+        mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
+                BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1);
+        if (delayAfterDisconnection > 0) {
+            Thread.sleep(delayAfterDisconnection);
+        }
+
+        // reconnection
+        mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2);
+        Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS);
+
+        // Verify disconnection has been cancelled and we're seeing two connections attempts,
+        // with the device connected at the end of the test
+        verify(mSpyDevInventory, times(2)).onSetA2dpSinkConnectionState(
+                any(BtHelper.BluetoothA2dpDeviceInfo.class),
+                ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED));
+        Assert.assertTrue("Mock device not connected",
+                mSpyDevInventory.isA2dpDeviceConnected(mFakeBtDevice));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 0309dbe..cae7b57 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -273,7 +273,7 @@
                 invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
         final Pair<Long, Long> persistedExecutionTimesUTC = new Pair<>(rtcNow, rtcNow + ONE_HOUR);
         final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
-                0 /* sourceUserId */, 0, 0, "someTag",
+                0 /* sourceUserId */, 0, "someTag",
                 invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis,
                 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
                 persistedExecutionTimesUTC, 0 /* innerFlagg */);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index f9e4c34..8e0d7be 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -311,8 +311,6 @@
     public void testFileLocation_Owner() {
         LockSettingsStorage storage = new LockSettingsStorage(getContext());
 
-        assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0));
-        assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0));
         assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0));
         assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0));
     }
@@ -436,10 +434,8 @@
                 PAYLOAD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD).toBytes();
         CredentialHash deserialized = CredentialHash.fromBytes(serialized);
 
-        assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version);
         assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type);
         assertArrayEquals(PAYLOAD, deserialized.hash);
-        assertFalse(deserialized.isBaseZeroPattern);
     }
 
     public void testCredentialHash_unserialize_versionGatekeeper() {
@@ -453,10 +449,8 @@
         };
         CredentialHash deserialized = CredentialHash.fromBytes(serialized);
 
-        assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version);
         assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type);
         assertArrayEquals(PAYLOAD, deserialized.hash);
-        assertFalse(deserialized.isBaseZeroPattern);
 
         // Make sure the constants we use on the wire do not change.
         assertEquals(-1, LockPatternUtils.CREDENTIAL_TYPE_NONE);
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
new file mode 100644
index 0000000..75e5847
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Process;
+import android.permission.IPermissionManager;
+import android.util.ArrayMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class AppsFilterTest {
+
+    private static final int DUMMY_CALLING_UID = 10345;
+
+    @Mock
+    IPermissionManager mPermissionManagerMock;
+
+    @Mock
+    AppsFilter.ConfigProvider mConfigProviderMock;
+
+    @Mock
+    AppOpsManager mAppOpsManager;
+
+    private Map<String, PackageParser.Package> mExisting = new ArrayMap<>();
+
+    private static PackageBuilder pkg(String packageName) {
+        return new PackageBuilder(packageName)
+                .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.R);
+    }
+
+    private static PackageBuilder pkg(String packageName, Intent... queries) {
+        return pkg(packageName).setQueriesIntents(queries);
+    }
+
+    private static PackageBuilder pkg(String packageName, String... queriesPackages) {
+        return pkg(packageName).setQueriesPackages(queriesPackages);
+    }
+
+    private static PackageBuilder pkg(String packageName, IntentFilter... filters) {
+        final PackageBuilder packageBuilder = pkg(packageName).addActivity(
+                pkg -> new PackageParser.ParseComponentArgs(pkg, new String[1], 0, 0, 0, 0, 0, 0,
+                        new String[]{packageName}, 0, 0, 0), new ActivityInfo());
+        for (IntentFilter filter : filters) {
+            packageBuilder.addActivityIntentInfo(0 /* index */, activity -> {
+                final PackageParser.ActivityIntentInfo info =
+                        new PackageParser.ActivityIntentInfo(activity);
+                if (filter.countActions() > 0) {
+                    filter.actionsIterator().forEachRemaining(info::addAction);
+                }
+                if (filter.countCategories() > 0) {
+                    filter.actionsIterator().forEachRemaining(info::addAction);
+                }
+                if (filter.countDataAuthorities() > 0) {
+                    filter.authoritiesIterator().forEachRemaining(info::addDataAuthority);
+                }
+                if (filter.countDataSchemes() > 0) {
+                    filter.schemesIterator().forEachRemaining(info::addDataScheme);
+                }
+                return info;
+            });
+        }
+        return packageBuilder;
+    }
+
+    @Before
+    public void setup() throws Exception {
+        mExisting = new ArrayMap<>();
+
+        MockitoAnnotations.initMocks(this);
+        when(mPermissionManagerMock
+                .checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        when(mConfigProviderMock.isEnabled()).thenReturn(true);
+        when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
+                DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_DEFAULT);
+    }
+
+    @Test
+    public void testQueriesAction_FilterMatches() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter,
+                pkg("com.some.package", new IntentFilter("TEST_ACTION"))).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package", new Intent("TEST_ACTION"))).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testQueriesAction_NoMatchingAction_Filters() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter,
+                pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package", new Intent("TEST_ACTION"))).build();
+
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package",
+                new Intent("TEST_ACTION")).setApplicationInfoTargetSdkVersion(
+                Build.VERSION_CODES.P)).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testNoQueries_Filters() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testForceQueryable_DoesntFilter() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target =
+                simulateAddPackage(appsFilter, pkg("com.some.package").setForceQueryable(true))
+                        .build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testForceQueryableByDevice_SystemCaller_DoesntFilter() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{"com.some.package"}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"))
+                .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                .build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testForceQueryableByDevice_NonSystemCaller_Filters() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{"com.some.package"}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+
+    @Test
+    public void testSystemQueryable_DoesntFilter() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, true /* system force queryable */);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"))
+                .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                .build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testQueriesPackage_DoesntFilter() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package", "com.some.package")).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testNoQueries_AppOpModeDeny_Filters() {
+        when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
+                DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_ERRORED);
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testNoQueries_AppOpModeAllow_DoesntFilter() {
+        when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
+                DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_ALLOWED);
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testNoQueries_AppOpModeIgnore_Filters() {
+        when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
+                DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_IGNORED);
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testNoQueries_FeatureOff_DoesntFilter() {
+        when(mConfigProviderMock.isEnabled()).thenReturn(false);
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package")).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    @Test
+    public void testSystemUid_DoesntFilter() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+
+        assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(
+                Process.FIRST_APPLICATION_UID - 1, null, target, 0));
+    }
+
+    @Test
+    public void testNonSystemUid_NoCallingSetting_Filters() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, null, target, 0));
+    }
+
+    @Test
+    public void testNoTargetPackage_filters() {
+        final AppsFilter appsFilter =
+                new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+                        new String[]{}, false);
+
+        PackageSetting target = new PackageSettingBuilder()
+                .setName("com.some.package")
+                .setCodePath("/")
+                .setResourcePath("/")
+                .setPVersionCode(1L)
+                .build();
+        PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package", new Intent("TEST_ACTION"))).build();
+
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+    }
+
+    private PackageSettingBuilder simulateAddPackage(AppsFilter filter,
+            PackageBuilder newPkgBuilder) {
+        PackageParser.Package newPkg = newPkgBuilder.build();
+        filter.addPackage(newPkg, mExisting);
+        mExisting.put(newPkg.packageName, newPkg);
+        return new PackageSettingBuilder()
+                .setPackage(newPkg)
+                .setName(newPkg.packageName)
+                .setCodePath("/")
+                .setResourcePath("/")
+                .setPVersionCode(1L);
+    }
+
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
index 470d4fa..c38672c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
@@ -16,10 +16,16 @@
 
 package com.android.server.pm;
 
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageParser;
 
 import com.android.internal.util.ArrayUtils;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
 class PackageBuilder {
     final PackageParser.Package mPkg;
 
@@ -119,4 +125,52 @@
         mPkg.applicationInfo.flags |= flag;
         return this;
     }
+
+    public PackageBuilder setApplicationInfoTargetSdkVersion(int versionCode) {
+        mPkg.applicationInfo.targetSdkVersion = versionCode;
+        return this;
+    }
+
+    public PackageBuilder setQueriesIntents(Collection<Intent> queriesIntents) {
+        mPkg.mQueriesIntents = new ArrayList<>(queriesIntents);
+        return this;
+    }
+
+    public PackageBuilder setQueriesIntents(Intent... intents) {
+        return setQueriesIntents(Arrays.asList(intents));
+    }
+
+    public PackageBuilder setQueriesPackages(Collection<String> queriesPackages) {
+        mPkg.mQueriesPackages = new ArrayList<>(queriesPackages);
+        return this;
+    }
+
+    public PackageBuilder setQueriesPackages(String... queriesPackages) {
+        return setQueriesPackages(Arrays.asList(queriesPackages));
+    }
+
+    public PackageBuilder setForceQueryable(boolean forceQueryable) {
+        mPkg.mForceQueryable = forceQueryable;
+        return this;
+    }
+
+    public interface ParseComponentArgsCreator {
+        PackageParser.ParseComponentArgs create(PackageParser.Package pkg);
+    }
+
+    public PackageBuilder addActivity(ParseComponentArgsCreator argsCreator, ActivityInfo info) {
+        mPkg.activities.add(new PackageParser.Activity(argsCreator.create(mPkg), info));
+        return this;
+    }
+
+    public interface ActivityIntentInfoCreator {
+        PackageParser.ActivityIntentInfo create(PackageParser.Activity activity);
+    }
+
+    public PackageBuilder addActivityIntentInfo(
+            int activityIndex, ActivityIntentInfoCreator creator) {
+        final PackageParser.Activity activity = mPkg.activities.get(activityIndex);
+        activity.intents.add(creator.create(activity));
+        return this;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index b42cfd8..06c6314 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.util.SparseArray;
 
@@ -41,6 +42,12 @@
     private long[] mUsesStaticLibrariesVersions;
     private String mVolumeUuid;
     private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
+    private PackageParser.Package mPkg;
+
+    public PackageSettingBuilder setPackage(PackageParser.Package pkg) {
+        this.mPkg = pkg;
+        return this;
+    }
 
     public PackageSettingBuilder setName(String name) {
         this.mName = name;
@@ -144,6 +151,7 @@
                 mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
                 mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
                 mUsesStaticLibrariesVersions);
+        packageSetting.pkg = mPkg;
         packageSetting.volumeUuid = this.mVolumeUuid;
         for (int i = 0; i < mUserStates.size(); i++) {
             packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index cc70ef8..05905d9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -34,9 +34,7 @@
 import static org.junit.Assert.assertNotSame;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
@@ -48,6 +46,7 @@
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
 
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
@@ -62,6 +61,7 @@
 
 @RunWith(MockitoJUnitRunner.class)
 @Presubmit
+// TODO: shared user tests
 public class ScanTests {
 
     private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
@@ -70,12 +70,38 @@
     PackageAbiHelper mMockPackageAbiHelper;
     @Mock
     UserManagerInternal mMockUserManager;
+    @Mock
+    PackageManagerService.Injector mMockInjector;
+
+    @Before
+    public void setupInjector() {
+        when(mMockInjector.getAbiHelper()).thenReturn(mMockPackageAbiHelper);
+        when(mMockInjector.getUserManagerInternal()).thenReturn(mMockUserManager);
+    }
 
     @Before
     public void setupDefaultUser() {
         when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
     }
 
+    @Before
+    public void setupDefaultAbiBehavior() throws Exception {
+        when(mMockPackageAbiHelper.derivePackageAbi(
+                any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
+                .thenReturn(new Pair<>(
+                        new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
+                        new PackageAbiHelper.NativeLibraryPaths(
+                                "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
+        when(mMockPackageAbiHelper.getNativeLibraryPaths(
+                any(PackageParser.Package.class), any(File.class)))
+                .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
+                        "getRootDir", true, "getNativeDir", "getNativeDir2"
+                ));
+        when(mMockPackageAbiHelper.getBundledAppAbis(
+                any(PackageParser.Package.class)))
+                .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
+    }
+
     @Test
     public void newInstallSimpleAllNominal() throws Exception {
         final PackageManagerService.ScanRequest scanRequest =
@@ -84,15 +110,11 @@
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                         .build();
 
-
         final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
 
         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
         assertThat(scanResult.existingSettingCopied, is(false));
-        verify(mMockPackageAbiHelper, never()).derivePackageAbi(any(PackageParser.Package.class),
-                anyString() /*abioverride*/, anyBoolean() /*extractNativeLibs*/);
-        verify(mMockPackageAbiHelper).setNativeLibraryPaths(
-                scanResult.pkgSetting.pkg, PackageManagerService.sAppLib32InstallDir);
+        assertPathsNotDerived(scanResult);
     }
 
     @Test
@@ -162,10 +184,7 @@
         assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
         assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
 
-        verify(mMockPackageAbiHelper, never()).derivePackageAbi(any(PackageParser.Package.class),
-                anyString() /*abioverride*/, anyBoolean() /*extractNativeLibs*/);
-        verify(mMockPackageAbiHelper).setNativeLibraryPaths(
-                scanResult.pkgSetting.pkg, PackageManagerService.sAppLib32InstallDir);
+        assertPathsNotDerived(scanResult);
     }
 
     @Test
@@ -293,12 +312,13 @@
                         .build();
 
 
-        executeScan(new ScanRequestBuilder(basicPackage)
+        final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
+                basicPackage)
                 .setPkgSetting(pkgSetting)
                 .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
                 .build());
 
-        verify(mMockPackageAbiHelper).derivePackageAbi(basicPackage, "testOverride", true);
+        assertAbiAndPathssDerived(scanResult);
     }
 
     @Test
@@ -389,7 +409,7 @@
 
         final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
                 createBasicScanRequestBuilder(basicPackage).build(),
-                new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+                mMockInjector,
                 true /*isUnderFactoryTest*/,
                 System.currentTimeMillis());
 
@@ -436,7 +456,7 @@
             PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
         return PackageManagerService.scanPackageOnlyLI(
                 scanRequest,
-                new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+                mMockInjector,
                 false /*isUnderFactoryTest*/,
                 System.currentTimeMillis());
     }
@@ -484,7 +504,7 @@
         assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
 
         final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
-        verifyBasicApplicationInfo(scanResult, applicationInfo);
+        assertBasicApplicationInfo(scanResult, applicationInfo);
 
     }
 
@@ -497,14 +517,12 @@
         assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
         assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
         assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
-        assertThat(pkgSetting.legacyNativeLibraryPathString,
-                is("/data/tmp/randompath/base.apk:/lib"));
         assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
         assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
         assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
     }
 
-    private static void verifyBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
+    private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
             ApplicationInfo applicationInfo) {
         assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
 
@@ -517,4 +535,25 @@
         assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
         assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
     }
+
+    private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
+        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+        assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
+        assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
+
+        assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
+        assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
+        assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
+        assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
+        assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
+    }
+
+    private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
+        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+        assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
+        assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
+        assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
+        assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
+        assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 1bda412..88de250 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -23,7 +23,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
@@ -59,6 +62,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.view.Display;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -157,6 +161,10 @@
         mResourcesSpy = spy(mContextSpy.getResources());
         when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
 
+        when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
+    }
+
+    private PowerManagerService createService() {
         mService = new PowerManagerService(mContextSpy, new Injector() {
             @Override
             Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
@@ -166,7 +174,7 @@
 
             @Override
             SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
-                return mock(SuspendBlocker.class);
+                return super.createSuspendBlocker(service, name);
             }
 
             @Override
@@ -191,6 +199,7 @@
                 return mAmbientDisplayConfigurationMock;
             }
         });
+        return mService;
     }
 
     @After
@@ -262,6 +271,7 @@
 
     @Test
     public void testUpdatePowerScreenPolicy_UpdateDisplayPowerRequest() {
+        createService();
         mService.updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
         assertThat(mDisplayPowerRequest.lowPowerMode).isEqualTo(BATTERY_SAVER_ENABLED);
         assertThat(mDisplayPowerRequest.screenLowPowerBrightnessFactor)
@@ -270,6 +280,7 @@
 
     @Test
     public void testGetLastShutdownReasonInternal() {
+        createService();
         SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "shutdown,thermal");
         int reason = mService.getLastShutdownReasonInternal(TEST_LAST_REBOOT_PROPERTY);
         SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "");
@@ -278,6 +289,7 @@
 
     @Test
     public void testGetDesiredScreenPolicy_WithVR() throws Exception {
+        createService();
         // Brighten up the screen
         mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
         assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
@@ -307,11 +319,13 @@
 
     @Test
     public void testWakefulnessAwake_InitialValue() throws Exception {
+        createService();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
     }
 
     @Test
     public void testWakefulnessSleep_NoDozeSleepFlag() throws Exception {
+        createService();
         // Start with AWAKE state
         startSystem();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
@@ -324,6 +338,7 @@
 
     @Test
     public void testWakefulnessAwake_AcquireCausesWakeup() throws Exception {
+        createService();
         startSystem();
         forceSleep();
 
@@ -355,6 +370,7 @@
 
     @Test
     public void testWakefulnessAwake_IPowerManagerWakeUp() throws Exception {
+        createService();
         startSystem();
         forceSleep();
         mService.getBinderServiceInstance().wakeUp(SystemClock.uptimeMillis(),
@@ -369,6 +385,8 @@
     @Test
     public void testWakefulnessAwake_ShouldWakeUpWhenPluggedIn() throws Exception {
         boolean powerState;
+
+        createService();
         startSystem();
         forceSleep();
 
@@ -444,6 +462,7 @@
 
     @Test
     public void testWakefulnessDoze_goToSleep() throws Exception {
+        createService();
         // Start with AWAKE state
         startSystem();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
@@ -457,6 +476,7 @@
     @Test
     public void testWasDeviceIdleFor_true() {
         int interval = 1000;
+        createService();
         mService.onUserActivity();
         SystemClock.sleep(interval + 1 /* just a little more */);
         assertThat(mService.wasDeviceIdleForInternal(interval)).isTrue();
@@ -465,12 +485,14 @@
     @Test
     public void testWasDeviceIdleFor_false() {
         int interval = 1000;
+        createService();
         mService.onUserActivity();
         assertThat(mService.wasDeviceIdleForInternal(interval)).isFalse();
     }
 
     @Test
     public void testForceSuspend_putsDeviceToSleep() {
+        createService();
         mService.systemReady(null);
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -497,6 +519,8 @@
         final int flags = PowerManager.PARTIAL_WAKE_LOCK;
         final String pkg = mContextSpy.getOpPackageName();
 
+        createService();
+
         // Set up the Notification mock to keep track of the wakelocks that are currently
         // active or disabled. We'll use this to verify that wakelocks are disabled when
         // they should be.
@@ -541,7 +565,54 @@
 
     @Test
     public void testForceSuspend_forceSuspendFailurePropogated() {
+        createService();
         when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false);
         assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
     }
+
+    @Test
+    public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() throws Exception {
+        final String suspendBlockerName = "PowerManagerService.Display";
+        final String tag = "acq_causes_wakeup";
+        final String packageName = "pkg.name";
+        final IBinder token = new Binder();
+
+        final boolean[] isAcquired = new boolean[1];
+        doAnswer(inv -> {
+            if (suspendBlockerName.equals(inv.getArguments()[0])) {
+                isAcquired[0] = false;
+            }
+            return null;
+        }).when(mNativeWrapperMock).nativeReleaseSuspendBlocker(any());
+
+        doAnswer(inv -> {
+            if (suspendBlockerName.equals(inv.getArguments()[0])) {
+                isAcquired[0] = true;
+            }
+            return null;
+        }).when(mNativeWrapperMock).nativeAcquireSuspendBlocker(any());
+
+        // Need to create the service after we stub the mocks for this test because some of the
+        // mocks are used during the constructor.
+        createService();
+
+        // Start with AWAKE state
+        startSystem();
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertTrue(isAcquired[0]);
+
+        // Take a nap and verify we no longer hold the blocker
+        int flags = PowerManager.DOZE_WAKE_LOCK;
+        mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+                null /* workSource */, null /* historyTag */);
+        mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(),
+                PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING);
+        assertFalse(isAcquired[0]);
+
+        // Override the display state by DreamManager and verify is reacquires the blocker.
+        mService.getLocalServiceInstance()
+                .setDozeOverrideFromDreamManager(Display.STATE_ON, PowerManager.BRIGHTNESS_DEFAULT);
+        assertTrue(isAcquired[0]);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index f14e8d2..c1c0a30 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2005,6 +2005,73 @@
     }
 
     @Test
+    public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception {
+        final NotificationRecord notification = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        mService.addNotification(notification);
+        when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+
+        NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+                mService.new SnoozeNotificationRunnable(
+                notification.getKey(), 100, null);
+        snoozeNotificationRunnable.run();
+        NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
+                mService.new SnoozeNotificationRunnable(
+                notification.getKey(), 100, null);
+        snoozeNotificationRunnable.run();
+
+        // snooze twice
+        verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
+    }
+
+    @Test
+    public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() throws Exception {
+        final NotificationRecord notification = generateNotificationRecord(
+                mTestNotificationChannel, 1, "group", true);
+        mService.addNotification(notification);
+        when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+
+        NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+                mService.new SnoozeNotificationRunnable(
+                notification.getKey(), 100, null);
+        snoozeNotificationRunnable.run();
+        NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
+                mService.new SnoozeNotificationRunnable(
+                notification.getKey(), 100, null);
+        snoozeNotificationRunnable.run();
+
+        // snooze twice
+        verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
+    }
+
+    @Test
+    public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throws Exception {
+        final NotificationRecord notification = generateNotificationRecord(
+                mTestNotificationChannel, 1, "group", true);
+        final NotificationRecord notification2 = generateNotificationRecord(
+                mTestNotificationChannel, 2, "group", true);
+        mService.addNotification(notification);
+        mService.addNotification(notification2);
+        when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+        when(mSnoozeHelper.getNotifications(
+                anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>());
+
+        NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+                mService.new SnoozeNotificationRunnable(
+                        notification.getKey(), 100, null);
+        snoozeNotificationRunnable.run();
+        when(mSnoozeHelper.getNotifications(anyString(), anyString(), anyInt()))
+                .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2)));
+        NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
+                mService.new SnoozeNotificationRunnable(
+                        notification.getKey(), 100, null);
+        snoozeNotificationRunnable.run();
+
+        // snooze twice
+        verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong());
+    }
+
+    @Test
     public void testSnoozeRunnable_snoozeNonGrouped() throws Exception {
         final NotificationRecord nonGrouped = generateNotificationRecord(
                 mTestNotificationChannel, 1, null, false);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 1e64543..2e7277f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -264,6 +264,63 @@
     }
 
     @Test
+    public void testGetSnoozedGroupNotifications() throws Exception {
+        IntArray profileIds = new IntArray();
+        profileIds.add(UserHandle.USER_CURRENT);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
+        NotificationRecord r = getNotificationRecord("pkg", 1, "tag",
+                UserHandle.CURRENT, "group", true);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag",
+                UserHandle.CURRENT, "group", true);
+        NotificationRecord r3 = getNotificationRecord("pkg2", 3, "tag",
+                UserHandle.CURRENT, "group", true);
+        NotificationRecord r4 = getNotificationRecord("pkg2", 4, "tag",
+                UserHandle.CURRENT, "group", true);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.snooze(r3, 1000);
+        mSnoozeHelper.snooze(r4, 1000);
+
+        assertEquals(2,
+                mSnoozeHelper.getNotifications("pkg", "group", UserHandle.USER_CURRENT).size());
+    }
+
+    @Test
+    public void testGetSnoozedNotificationByKey() throws Exception {
+        IntArray profileIds = new IntArray();
+        profileIds.add(UserHandle.USER_CURRENT);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
+        NotificationRecord r = getNotificationRecord("pkg", 1, "tag",
+                UserHandle.CURRENT, "group", true);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag",
+                UserHandle.CURRENT, "group", true);
+        NotificationRecord r3 = getNotificationRecord("pkg2", 3, "tag",
+                UserHandle.CURRENT, "group", true);
+        NotificationRecord r4 = getNotificationRecord("pkg2", 4, "tag",
+                UserHandle.CURRENT, "group", true);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.snooze(r3, 1000);
+        mSnoozeHelper.snooze(r4, 1000);
+
+        assertEquals(r, mSnoozeHelper.getNotification(r.getKey()));
+    }
+
+    @Test
+    public void testGetUnSnoozedNotificationByKey() throws Exception {
+        IntArray profileIds = new IntArray();
+        profileIds.add(UserHandle.USER_CURRENT);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
+        NotificationRecord r = getNotificationRecord("pkg", 1, "tag",
+                UserHandle.CURRENT, "group", true);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag",
+                UserHandle.CURRENT, "group", true);
+        mSnoozeHelper.snooze(r2, 1000);
+
+        assertEquals(null, mSnoozeHelper.getNotification(r.getKey()));
+    }
+
+    @Test
     public void repostGroupSummary_onlyFellowGroupChildren() throws Exception {
         NotificationRecord r = getNotificationRecord(
                 "pkg", 1, "one", UserHandle.SYSTEM, "group1", false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index a08923b..3d94467 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -842,4 +842,51 @@
         // Ensure the activity is moved to secondary display.
         assertEquals(secondaryDisplay, topActivity.getDisplay());
     }
+
+    /**
+     * This test ensures that starting an activity with the freeze-task-list activity option will
+     * actually freeze the task list
+     */
+    @Test
+    public void testFreezeTaskListActivityOption() {
+        RecentTasks recentTasks = mock(RecentTasks.class);
+        mService.mStackSupervisor.setRecentTasks(recentTasks);
+        doReturn(true).when(recentTasks).isCallerRecents(anyInt());
+
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setFreezeRecentTasksReordering();
+
+        starter.setReason("testFreezeTaskListActivityOption")
+                .setActivityOptions(new SafeActivityOptions(options))
+                .execute();
+
+        verify(recentTasks, times(1)).setFreezeTaskListReordering();
+        verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout();
+    }
+
+    /**
+     * This test ensures that if we froze the task list as a part of starting an activity that fails
+     * to start, that we also reset the task list.
+     */
+    @Test
+    public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
+        RecentTasks recentTasks = mock(RecentTasks.class);
+        mService.mStackSupervisor.setRecentTasks(recentTasks);
+        doReturn(true).when(recentTasks).isCallerRecents(anyInt());
+
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setFreezeRecentTasksReordering();
+
+        starter.setReason("testFreezeTaskListActivityOptionFailedStart")
+                .setActivityOptions(new SafeActivityOptions(options))
+                .execute();
+
+        // Simulate a failed start
+        starter.postStartActivityProcessing(null, START_ABORTED, null);
+
+        verify(recentTasks, times(1)).setFreezeTaskListReordering();
+        verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
new file mode 100644
index 0000000..d8a9bb0
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+
+import androidx.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link ActivityTaskManagerService} class.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:ActivityTaskManagerServiceTests
+ */
+@MediumTest
+public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
+
+    @Before
+    public void setUp() throws Exception {
+        doReturn(false).when(mService).isBooting();
+        doReturn(true).when(mService).isBooted();
+    }
+
+    /** Verify that activity is finished correctly upon request. */
+    @Test
+    public void testActivityFinish() {
+        final TestActivityStack stack =
+                (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
+        final ActivityRecord activity = stack.getChildAt(0).getTopActivity();
+        assertTrue("Activity must be finished", mService.finishActivity(activity.appToken,
+                0 /* resultCode */, null /* resultData */,
+                Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
+        assertTrue(activity.finishing);
+
+        assertTrue("Duplicate activity finish request must also return 'true'",
+                mService.finishActivity(activity.appToken, 0 /* resultCode */,
+                        null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
+    }
+}
+
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 7f35dac..d9566a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -504,6 +504,21 @@
         assertEquals(stackBounds, mToken.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
     }
 
+    @Test
+    public void testHasStartingWindow() {
+        final WindowManager.LayoutParams attrs =
+                new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING);
+        final WindowTestUtils.TestWindowState startingWindow = createWindowState(attrs, mToken);
+        mToken.startingDisplayed = true;
+        mToken.addWindow(startingWindow);
+        assertTrue("Starting window should be present", mToken.hasStartingWindow());
+        mToken.startingDisplayed = false;
+        assertTrue("Starting window should be present", mToken.hasStartingWindow());
+
+        mToken.removeChild(startingWindow);
+        assertFalse("Starting window should not be present", mToken.hasStartingWindow());
+    }
+
     private void assertHasStartingWindow(AppWindowToken atoken) {
         assertNotNull(atoken.startingSurface);
         assertNotNull(atoken.mStartingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 29398b6..2cebebf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1251,6 +1251,22 @@
         assertEquals(startingBounds, adjustedBounds);
     }
 
+    @Test
+    public void testNoMultiDisplaySupports() {
+        final boolean orgValue = mService.mSupportsMultiDisplay;
+        final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+        mCurrent.mPreferredDisplayId = display.mDisplayId;
+
+        try {
+            mService.mSupportsMultiDisplay = false;
+            assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                    mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+            assertEquals(DEFAULT_DISPLAY, mResult.mPreferredDisplayId);
+        } finally {
+            mService.mSupportsMultiDisplay = orgValue;
+        }
+    }
+
     private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
         final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
         display.setWindowingMode(windowingMode);
diff --git a/startop/scripts/app_startup/app_startup_runner.py b/startop/scripts/app_startup/app_startup_runner.py
index 7cba780..eb582f9 100755
--- a/startop/scripts/app_startup/app_startup_runner.py
+++ b/startop/scripts/app_startup/app_startup_runner.py
@@ -32,21 +32,25 @@
 import os
 import sys
 import tempfile
+from datetime import timedelta
 from typing import Any, Callable, Iterable, List, NamedTuple, TextIO, Tuple, \
-    TypeVar, Union
+    TypeVar, Union, Optional
 
 # local import
 DIR = os.path.abspath(os.path.dirname(__file__))
 sys.path.append(os.path.dirname(DIR))
-import app_startup.run_app_with_prefetch as run_app_with_prefetch
-import app_startup.lib.args_utils as args_utils
-from app_startup.lib.data_frame import DataFrame
 import lib.cmd_utils as cmd_utils
 import lib.print_utils as print_utils
+import iorap.compiler as compiler
+from app_startup.run_app_with_prefetch import PrefetchAppRunner
+import app_startup.lib.args_utils as args_utils
+from app_startup.lib.data_frame import DataFrame
+from app_startup.lib.perfetto_trace_collector import PerfettoTraceCollector
 
 # The following command line options participate in the combinatorial generation.
 # All other arguments have a global effect.
-_COMBINATORIAL_OPTIONS = ['package', 'readahead', 'compiler_filter', 'activity']
+_COMBINATORIAL_OPTIONS = ['package', 'readahead', 'compiler_filter',
+                          'activity', 'trace_duration']
 _TRACING_READAHEADS = ['mlock', 'fadvise']
 _FORWARD_OPTIONS = {'loop_count': '--count'}
 _RUN_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)),
@@ -54,17 +58,29 @@
 
 CollectorPackageInfo = NamedTuple('CollectorPackageInfo',
                                   [('package', str), ('compiler_filter', str)])
-_COLLECTOR_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)),
-                                 '../iorap/collector')
-_COLLECTOR_TIMEOUT_MULTIPLIER = 10  # take the regular --timeout and multiply
+_COMPILER_SCRIPT = os.path.join(os.path.dirname(os.path.dirname(
+    os.path.realpath(__file__))), 'iorap/compiler.py')
 # by 2; systrace starts up slowly.
 
 _UNLOCK_SCREEN_SCRIPT = os.path.join(
     os.path.dirname(os.path.realpath(__file__)), 'unlock_screen')
 
+RunCommandArgs = NamedTuple('RunCommandArgs',
+                            [('package', str),
+                             ('readahead', str),
+                             ('activity', Optional[str]),
+                             ('compiler_filter', Optional[str]),
+                             ('timeout', Optional[int]),
+                             ('debug', bool),
+                             ('simulate', bool),
+                             ('input', Optional[str]),
+                             ('trace_duration', Optional[timedelta])])
+
 # This must be the only mutable global variable. All other global variables are constants to avoid magic literals.
 _debug = False  # See -d/--debug flag.
 _DEBUG_FORCE = None  # Ignore -d/--debug if this is not none.
+_PERFETTO_TRACE_DURATION_MS = 5000 # milliseconds
+_PERFETTO_TRACE_DURATION = timedelta(milliseconds=_PERFETTO_TRACE_DURATION_MS)
 
 # Type hinting names.
 T = TypeVar('T')
@@ -113,26 +129,15 @@
   optional_named.add_argument('-in', '--inodes', dest='inodes', type=str,
                               action='store',
                               help='Path to inodes file (system/extras/pagecache/pagecache.py -d inodes)')
+  optional_named.add_argument('--compiler-trace-duration-ms',
+                              dest='trace_duration',
+                              type=lambda ms_str: timedelta(milliseconds=int(ms_str)),
+                              action='append',
+                              help='The trace duration (milliseconds) in '
+                                   'compilation')
 
   return parser.parse_args(argv)
 
-def make_script_command_with_temp_output(script: str,
-                                         args: List[str],
-                                         **kwargs) -> Tuple[str, TextIO]:
-  """
-  Create a command to run a script given the args.
-  Appends --count <loop_count> --output <tmp-file-name>.
-  Returns a tuple (cmd, tmp_file)
-  """
-  tmp_output_file = tempfile.NamedTemporaryFile(mode='r')
-  cmd = [script] + args
-  for key, value in kwargs.items():
-    cmd += ['--%s' % (key), "%s" % (value)]
-  if _debug:
-    cmd += ['--verbose']
-  cmd = cmd + ["--output", tmp_output_file.name]
-  return cmd, tmp_output_file
-
 def key_to_cmdline_flag(key: str) -> str:
   """Convert key into a command line flag, e.g. 'foo-bars' -> '--foo-bar' """
   if key.endswith("s"):
@@ -153,26 +158,26 @@
     args.append(value)
   return args
 
-def run_collector_script(collector_info: CollectorPackageInfo,
-                         inodes_path: str,
-                         timeout: int,
-                         simulate: bool) -> Tuple[bool, TextIO]:
-  """Run collector to collect prefetching trace. """
-  # collector_args = ["--package", package_name]
-  collector_args = as_run_command(collector_info)
-  # TODO: forward --wait_time for how long systrace runs?
-  # TODO: forward --trace_buffer_size for size of systrace buffer size?
-  collector_cmd, collector_tmp_output_file = make_script_command_with_temp_output(
-      _COLLECTOR_SCRIPT, collector_args, inodes=inodes_path)
+def run_perfetto_collector(collector_info: CollectorPackageInfo,
+                           timeout: int,
+                           simulate: bool) -> Tuple[bool, TextIO]:
+  """Run collector to collect prefetching trace.
 
-  collector_timeout = timeout and _COLLECTOR_TIMEOUT_MULTIPLIER * timeout
-  (collector_passed, collector_script_output) = \
-    cmd_utils.execute_arbitrary_command(collector_cmd,
-                                        collector_timeout,
-                                        shell=False,
-                                        simulate=simulate)
+  Returns:
+    A tuple of whether the collection succeeds and the generated trace file.
+  """
+  tmp_output_file = tempfile.NamedTemporaryFile()
 
-  return collector_passed, collector_tmp_output_file
+  collector = PerfettoTraceCollector(package=collector_info.package,
+                                     activity=None,
+                                     compiler_filter=collector_info.compiler_filter,
+                                     timeout=timeout,
+                                     simulate=simulate,
+                                     trace_duration=_PERFETTO_TRACE_DURATION,
+                                     save_destination_file_path=tmp_output_file.name)
+  result = collector.run()
+
+  return result is not None, tmp_output_file
 
 def parse_run_script_csv_file(csv_file: TextIO) -> DataFrame:
   """Parse a CSV file full of integers into a DataFrame."""
@@ -206,9 +211,54 @@
 
   return DataFrame(d)
 
+def compile_perfetto_trace(inodes_path: str,
+                           perfetto_trace_file: str,
+                           trace_duration: Optional[timedelta]) -> TextIO:
+  compiler_trace_file = tempfile.NamedTemporaryFile()
+  argv = [_COMPILER_SCRIPT, '-i', inodes_path, '--perfetto-trace',
+          perfetto_trace_file, '-o', compiler_trace_file.name]
+
+  if trace_duration is not None:
+    argv += ['--duration', str(int(trace_duration.total_seconds()
+                               * PerfettoTraceCollector.MS_PER_SEC))]
+
+  print_utils.debug_print(argv)
+  compiler.main(argv)
+  return compiler_trace_file
+
+def execute_run_using_perfetto_trace(collector_info,
+                                     run_combos: Iterable[RunCommandArgs],
+                                     simulate: bool,
+                                     inodes_path: str,
+                                     timeout: int) -> DataFrame:
+  """ Executes run based on perfetto trace. """
+  passed, perfetto_trace_file = run_perfetto_collector(collector_info,
+                                                       timeout,
+                                                       simulate)
+  if not passed:
+    raise RuntimeError('Cannot run perfetto collector!')
+
+  with perfetto_trace_file:
+    for combos in run_combos:
+      if combos.readahead in _TRACING_READAHEADS:
+        if simulate:
+          compiler_trace_file = tempfile.NamedTemporaryFile()
+        else:
+          compiler_trace_file = compile_perfetto_trace(inodes_path,
+                                                       perfetto_trace_file.name,
+                                                       combos.trace_duration)
+        with compiler_trace_file:
+          combos = combos._replace(input=compiler_trace_file.name)
+          print_utils.debug_print(combos)
+          output = PrefetchAppRunner(**combos._asdict()).run()
+      else:
+        print_utils.debug_print(combos)
+        output = PrefetchAppRunner(**combos._asdict()).run()
+
+      yield DataFrame(dict((x, [y]) for x, y in output)) if output else None
+
 def execute_run_combos(
-    grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[
-      run_app_with_prefetch.RunCommandArgs]]],
+    grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[RunCommandArgs]]],
     simulate: bool,
     inodes_path: str,
     timeout: int):
@@ -219,19 +269,11 @@
                                       shell=False)
 
   for collector_info, run_combos in grouped_run_combos:
-    for combos in run_combos:
-      args = as_run_command(combos)
-      if combos.readahead in _TRACING_READAHEADS:
-        passed, collector_tmp_output_file = run_collector_script(collector_info,
-                                                                 inodes_path,
-                                                                 timeout,
-                                                                 simulate)
-        combos = combos._replace(input=collector_tmp_output_file.name)
-
-      print_utils.debug_print(combos)
-      output = run_app_with_prefetch.run_test(combos)
-
-      yield DataFrame(dict((x, [y]) for x, y in output)) if output else None
+    yield from execute_run_using_perfetto_trace(collector_info,
+                                                run_combos,
+                                                simulate,
+                                                inodes_path,
+                                                timeout)
 
 def gather_results(commands: Iterable[Tuple[DataFrame]],
                    key_list: List[str], value_list: List[Tuple[str, ...]]):
@@ -307,7 +349,7 @@
   output_file = opts.output and open(opts.output, 'w') or sys.stdout
 
   combos = lambda: args_utils.generate_run_combinations(
-      run_app_with_prefetch.RunCommandArgs,
+      RunCommandArgs,
       coerce_to_list(vars(opts)),
       opts.loop_count)
   print_utils.debug_print_gen("run combinations: ", combos())
diff --git a/startop/scripts/app_startup/app_startup_runner_test.py b/startop/scripts/app_startup/app_startup_runner_test.py
index 9aa7014..42ea5f0 100755
--- a/startop/scripts/app_startup/app_startup_runner_test.py
+++ b/startop/scripts/app_startup/app_startup_runner_test.py
@@ -91,7 +91,8 @@
   # Combine it with all of the "optional" parameters' default values.
   """
   d = {'compiler_filters': None, 'simulate': False, 'debug': False,
-       'output': None, 'timeout': 10, 'loop_count': 1, 'inodes': None}
+       'output': None, 'timeout': 10, 'loop_count': 1, 'inodes': None,
+       'trace_duration': None}
   d.update(kwargs)
   return d
 
@@ -159,19 +160,6 @@
   assert asr.key_to_cmdline_flag("ba_r") == "--ba-r"
   assert asr.key_to_cmdline_flag("ba_zs") == "--ba-z"
 
-def test_make_script_command_with_temp_output():
-  cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script",
-                                                               args=[], count=1)
-  with tmp_file:
-    assert cmd_str == ["fake_script", "--count", "1", "--output", tmp_file.name]
-
-  cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script",
-                                                               args=['a', 'b'],
-                                                               count=2)
-  with tmp_file:
-    assert cmd_str == ["fake_script", "a", "b", "--count", "2", "--output",
-                       tmp_file.name]
-
 def test_parse_run_script_csv_file():
   # empty file -> empty list
   f = io.StringIO("")
diff --git a/startop/scripts/app_startup/lib/adb_utils.py b/startop/scripts/app_startup/lib/adb_utils.py
index 0e0065d..1c60a17 100644
--- a/startop/scripts/app_startup/lib/adb_utils.py
+++ b/startop/scripts/app_startup/lib/adb_utils.py
@@ -104,4 +104,21 @@
     return None
   displayed_time = result[result.rfind('+'):]
 
-  return parse_time_to_milliseconds(displayed_time)
\ No newline at end of file
+  return parse_time_to_milliseconds(displayed_time)
+
+def delete_file_on_device(file_path: str) -> None:
+  """ Deletes a file on the device. """
+  cmd_utils.run_adb_shell_command(
+    "[[ -f '{file_path}' ]] && rm -f '{file_path}' || "
+    "exit 0".format(file_path=file_path))
+
+def set_prop(property: str, value: str) -> None:
+  """ Sets property using adb shell. """
+  cmd_utils.run_adb_shell_command('setprop "{property}" "{value}"'.format(
+      property=property, value=value))
+
+def pull_file(device_file_path: str, output_file_path: str) -> None:
+  """ Pulls file from device to output """
+  cmd_utils.run_shell_command('adb pull "{device_file_path}" "{output_file_path}"'.
+      format(device_file_path=device_file_path,
+             output_file_path=output_file_path))
diff --git a/startop/scripts/app_startup/lib/app_runner.py b/startop/scripts/app_startup/lib/app_runner.py
new file mode 100644
index 0000000..78873fa
--- /dev/null
+++ b/startop/scripts/app_startup/lib/app_runner.py
@@ -0,0 +1,266 @@
+# Copyright 2019, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Class to run an app."""
+import os
+import sys
+from typing import Optional, List, Tuple
+
+# local import
+sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(
+    os.path.abspath(__file__)))))
+
+import app_startup.lib.adb_utils as adb_utils
+import lib.cmd_utils as cmd_utils
+import lib.print_utils as print_utils
+
+class AppRunnerListener(object):
+  """Interface for lisenter of AppRunner. """
+
+  def preprocess(self) -> None:
+    """Preprocess callback to initialized before the app is running. """
+    pass
+
+  def postprocess(self, pre_launch_timestamp: str) -> None:
+    """Postprocess callback to cleanup after the app is running.
+
+      param:
+        'pre_launch_timestamp': indicates the timestamp when the app is
+        launching.. """
+    pass
+
+  def metrics_selector(self, am_start_output: str,
+                       pre_launch_timestamp: str) -> None:
+    """A metrics selection callback that waits for the desired metrics to
+      show up in logcat.
+      params:
+        'am_start_output': indicates the output of app startup.
+        'pre_launch_timestamp': indicates the timestamp when the app is
+                        launching.
+      returns:
+        a string in the format of "<metric>=<value>\n<metric>=<value>\n..."
+        for further parsing. For example "TotalTime=123\nDisplayedTime=121".
+        Return an empty string if no metrics need to be parsed further.
+        """
+    pass
+
+class AppRunner(object):
+  """ Class to run an app. """
+  # static variables
+  DIR = os.path.abspath(os.path.dirname(__file__))
+  APP_STARTUP_DIR = os.path.dirname(DIR)
+  IORAP_COMMON_BASH_SCRIPT = os.path.realpath(os.path.join(DIR,
+                                                           '../../iorap/common'))
+  DEFAULT_TIMEOUT = 30 # seconds
+
+  def __init__(self,
+               package: str,
+               activity: Optional[str],
+               compiler_filter: Optional[str],
+               timeout: Optional[int],
+               simulate: bool):
+    self.package = package
+    self.simulate = simulate
+
+    # If the argument activity is None, try to set it.
+    self.activity = activity
+    if self.simulate:
+      self.activity = 'act'
+    if self.activity is None:
+      self.activity = AppRunner.get_activity(self.package)
+
+    self.compiler_filter = compiler_filter
+    self.timeout = timeout if timeout else AppRunner.DEFAULT_TIMEOUT
+
+    self.listeners = []
+
+  def add_callbacks(self, listener: AppRunnerListener):
+    self.listeners.append(listener)
+
+  def remove_callbacks(self, listener: AppRunnerListener):
+    self.listeners.remove(listener)
+
+  @staticmethod
+  def get_activity(package: str) -> str:
+    """ Tries to set the activity based on the package. """
+    passed, activity = cmd_utils.run_shell_func(
+        AppRunner.IORAP_COMMON_BASH_SCRIPT,
+        'get_activity_name',
+        [package])
+
+    if not passed or not activity:
+      raise ValueError(
+          'Activity name could not be found, invalid package name?!')
+
+    return activity
+
+  def configure_compiler_filter(self) -> bool:
+    """Configures compiler filter (e.g. speed).
+
+    Returns:
+      A bool indicates whether configure of compiler filer succeeds or not.
+    """
+    if not self.compiler_filter:
+      print_utils.debug_print('No --compiler-filter specified, don\'t'
+                              ' need to force it.')
+      return True
+
+    passed, current_compiler_filter_info = \
+      cmd_utils.run_shell_command(
+          '{} --package {}'.format(os.path.join(AppRunner.APP_STARTUP_DIR,
+                                                'query_compiler_filter.py'),
+                                   self.package))
+
+    if passed != 0:
+      return passed
+
+    # TODO: call query_compiler_filter directly as a python function instead of
+    #  these shell calls.
+    current_compiler_filter, current_reason, current_isa = \
+      current_compiler_filter_info.split(' ')
+    print_utils.debug_print('Compiler Filter={} Reason={} Isa={}'.format(
+        current_compiler_filter, current_reason, current_isa))
+
+    # Don't trust reasons that aren't 'unknown' because that means
+    #  we didn't manually force the compilation filter.
+    # (e.g. if any automatic system-triggered compilations are not unknown).
+    if current_reason != 'unknown' or \
+        current_compiler_filter != self.compiler_filter:
+      passed, _ = adb_utils.run_shell_command('{}/force_compiler_filter '
+                                              '--compiler-filter "{}" '
+                                              '--package "{}"'
+                                              ' --activity "{}'.
+                                                format(AppRunner.APP_STARTUP_DIR,
+                                                       self.compiler_filter,
+                                                       self.package,
+                                                       self.activity))
+    else:
+      adb_utils.debug_print('Queried compiler-filter matched requested '
+                            'compiler-filter, skip forcing.')
+      passed = False
+    return passed
+
+  def run(self) -> Optional[List[Tuple[str]]]:
+    """Runs an app.
+
+    Returns:
+      A list of (metric, value) tuples.
+    """
+    print_utils.debug_print('==========================================')
+    print_utils.debug_print('=====             START              =====')
+    print_utils.debug_print('==========================================')
+    # Run the preprocess.
+    for listener in self.listeners:
+      listener.preprocess()
+
+    # Ensure the APK is currently compiled with whatever we passed in
+    # via --compiler-filter.
+    # No-op if this option was not passed in.
+    if not self.configure_compiler_filter():
+      print_utils.error_print('Compiler filter configuration failed!')
+      return None
+
+    pre_launch_timestamp = adb_utils.logcat_save_timestamp()
+    # Launch the app.
+    results = self.launch_app(pre_launch_timestamp)
+
+    # Run the postprocess.
+    for listener in self.listeners:
+      listener.postprocess(pre_launch_timestamp)
+
+    return results
+
+  def launch_app(self, pre_launch_timestamp: str) -> Optional[List[Tuple[str]]]:
+    """ Launches the app.
+
+        Returns:
+          A list of (metric, value) tuples.
+    """
+    print_utils.debug_print('Running with timeout {}'.format(self.timeout))
+
+    passed, am_start_output = cmd_utils.run_shell_command('timeout {timeout} '
+                                                 '"{DIR}/launch_application" '
+                                                 '"{package}" '
+                                                 '"{activity}"'.
+                                                   format(timeout=self.timeout,
+                                                          DIR=AppRunner.APP_STARTUP_DIR,
+                                                          package=self.package,
+                                                          activity=self.activity))
+    if not passed and not self.simulate:
+      return None
+
+    return self.wait_for_app_finish(pre_launch_timestamp, am_start_output)
+
+  def wait_for_app_finish(self,
+                          pre_launch_timestamp: str,
+                          am_start_output:  str) -> Optional[List[Tuple[str]]]:
+    """ Wait for app finish and all metrics are shown in logcat.
+
+    Returns:
+      A list of (metric, value) tuples.
+    """
+    if self.simulate:
+      return [('TotalTime', '123')]
+
+    ret = []
+    for listener in self.listeners:
+      output = listener.metrics_selector(am_start_output,
+                                         pre_launch_timestamp)
+      ret = ret + AppRunner.parse_metrics_output(output)
+
+    return ret
+
+  @staticmethod
+  def parse_metrics_output(input: str) -> List[
+    Tuple[str, str, str]]:
+    """Parses output of app startup to metrics and corresponding values.
+
+    It converts 'a=b\nc=d\ne=f\n...' into '[(a,b,''),(c,d,''),(e,f,'')]'
+
+    Returns:
+      A list of tuples that including metric name, metric value and rest info.
+    """
+    all_metrics = []
+    for line in input.split('\n'):
+      if not line:
+        continue
+      splits = line.split('=')
+      if len(splits) < 2:
+        print_utils.error_print('Bad line "{}"'.format(line))
+        continue
+      metric_name = splits[0]
+      metric_value = splits[1]
+      rest = splits[2] if len(splits) > 2 else ''
+      if rest:
+        print_utils.error_print('Corrupt line "{}"'.format(line))
+      print_utils.debug_print('metric: "{metric_name}", '
+                              'value: "{metric_value}" '.
+                                format(metric_name=metric_name,
+                                     metric_value=metric_value))
+
+      all_metrics.append((metric_name, metric_value))
+    return all_metrics
+
+  @staticmethod
+  def parse_total_time( am_start_output: str) -> Optional[str]:
+    """Parses the total time from 'adb shell am start pkg' output.
+
+    Returns:
+      the total time of app startup.
+    """
+    for line in am_start_output.split('\n'):
+      if 'TotalTime:' in line:
+        return line[len('TotalTime:'):].strip()
+    return None
+
diff --git a/startop/scripts/app_startup/lib/app_runner_test.py b/startop/scripts/app_startup/lib/app_runner_test.py
new file mode 100644
index 0000000..33d233b
--- /dev/null
+++ b/startop/scripts/app_startup/lib/app_runner_test.py
@@ -0,0 +1,104 @@
+# Copyright 2019, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Unit tests for the AppRunner."""
+import os
+import sys
+from pathlib import Path
+
+from app_runner import AppRunner, AppRunnerListener
+from mock import Mock, call, patch
+
+# The path is "frameworks/base/startop/scripts/"
+sys.path.append(Path(os.path.realpath(__file__)).parents[2])
+import lib.cmd_utils as cmd_utils
+
+class AppRunnerTestListener(AppRunnerListener):
+  def preprocess(self) -> None:
+    cmd_utils.run_shell_command('pre'),
+
+  def postprocess(self, pre_launch_timestamp: str) -> None:
+    cmd_utils.run_shell_command('post'),
+
+  def metrics_selector(self, am_start_output: str,
+                       pre_launch_timestamp: str) -> None:
+    return 'TotalTime=123\n'
+
+RUNNER = AppRunner(package='music',
+                   activity='MainActivity',
+                   compiler_filter='speed',
+                   timeout=None,
+                   simulate=False)
+
+
+
+def test_configure_compiler_filter():
+  with patch('lib.cmd_utils.run_shell_command',
+             new_callable=Mock) as mock_run_shell_command:
+    mock_run_shell_command.return_value = (True, 'speed arm64 kUpToDate')
+
+    RUNNER.configure_compiler_filter()
+
+    calls = [call(os.path.realpath(
+        os.path.join(RUNNER.DIR,
+                     '../query_compiler_filter.py')) + ' --package music')]
+    mock_run_shell_command.assert_has_calls(calls)
+
+def test_parse_metrics_output():
+  input = 'a1=b1\nc1=d1\ne1=f1'
+  ret = RUNNER.parse_metrics_output(input)
+
+  assert ret == [('a1', 'b1'), ('c1', 'd1'), ('e1', 'f1')]
+
+def _mocked_run_shell_command(*args, **kwargs):
+  if args[0] == 'adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"':
+    return (True, "2019-07-02 23:20:06.972674825")
+  elif args[0] == 'adb shell ps | grep "music" | awk \'{print $2;}\'':
+    return (True, '9999')
+  else:
+    return (True, 'a1=b1\nc1=d1=d2\ne1=f1')
+
+@patch('app_startup.lib.adb_utils.blocking_wait_for_logcat_displayed_time')
+@patch('lib.cmd_utils.run_shell_command')
+def test_run(mock_run_shell_command,
+             mock_blocking_wait_for_logcat_displayed_time):
+  mock_run_shell_command.side_effect = _mocked_run_shell_command
+  mock_blocking_wait_for_logcat_displayed_time.return_value = 123
+
+  test_listener = AppRunnerTestListener()
+  RUNNER.add_callbacks(test_listener)
+
+  result = RUNNER.run()
+
+  RUNNER.remove_callbacks(test_listener)
+
+  calls = [call('pre'),
+           call(os.path.realpath(
+               os.path.join(RUNNER.DIR,
+                            '../query_compiler_filter.py')) +
+                ' --package music'),
+           call('adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"'),
+           call(
+               'timeout {timeout} "{DIR}/launch_application" "{package}" "{activity}"'
+                 .format(timeout=30,
+                         DIR=os.path.realpath(os.path.dirname(RUNNER.DIR)),
+                         package='music',
+                         activity='MainActivity',
+                         timestamp='2019-07-02 23:20:06.972674825')),
+           call('post')
+           ]
+  mock_run_shell_command.assert_has_calls(calls)
+  assert result == [('TotalTime', '123')]
+  assert len(RUNNER.listeners) == 0
\ No newline at end of file
diff --git a/startop/scripts/app_startup/lib/perfetto_trace_collector.py b/startop/scripts/app_startup/lib/perfetto_trace_collector.py
new file mode 100644
index 0000000..9ffb349
--- /dev/null
+++ b/startop/scripts/app_startup/lib/perfetto_trace_collector.py
@@ -0,0 +1,166 @@
+# Copyright 2019, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Class to collector perfetto trace."""
+import datetime
+import os
+import re
+import sys
+import time
+from datetime import timedelta
+from typing import Optional, List, Tuple
+
+# global variables
+DIR = os.path.abspath(os.path.dirname(__file__))
+
+sys.path.append(os.path.dirname(os.path.dirname(DIR)))
+
+import app_startup.lib.adb_utils as adb_utils
+from app_startup.lib.app_runner import AppRunner, AppRunnerListener
+import lib.print_utils as print_utils
+import lib.logcat_utils as logcat_utils
+import iorap.lib.iorapd_utils as iorapd_utils
+
+class PerfettoTraceCollector(AppRunnerListener):
+  """ Class to collect perfetto trace.
+
+      To set trace duration of perfetto, change the 'trace_duration_ms'.
+      To pull the generated perfetto trace on device, set the 'output'.
+  """
+  TRACE_FILE_SUFFIX = 'perfetto_trace.pb'
+  TRACE_DURATION_PROP = 'iorapd.perfetto.trace_duration_ms'
+  MS_PER_SEC  = 1000
+  DEFAULT_TRACE_DURATION = timedelta(milliseconds=5000) # 5 seconds
+  _COLLECTOR_TIMEOUT_MULTIPLIER = 10  # take the regular timeout and multiply
+
+  def __init__(self,
+               package: str,
+               activity: Optional[str],
+               compiler_filter: Optional[str],
+               timeout: Optional[int],
+               simulate: bool,
+               trace_duration: timedelta = DEFAULT_TRACE_DURATION,
+               save_destination_file_path: Optional[str] = None):
+    """ Initialize the perfetto trace collector. """
+    self.app_runner = AppRunner(package,
+                                activity,
+                                compiler_filter,
+                                timeout,
+                                simulate)
+    self.app_runner.add_callbacks(self)
+
+    self.trace_duration = trace_duration
+    self.save_destination_file_path = save_destination_file_path
+
+  def purge_file(self, suffix: str) -> None:
+    print_utils.debug_print('iorapd-perfetto: purge file in ' +
+                            self._get_remote_path())
+    adb_utils.delete_file_on_device(self._get_remote_path())
+
+  def run(self) -> Optional[List[Tuple[str]]]:
+    """Runs an app.
+
+    Returns:
+      A list of (metric, value) tuples.
+    """
+    return self.app_runner.run()
+
+  def preprocess(self):
+    # Sets up adb environment.
+    adb_utils.root()
+    adb_utils.disable_selinux()
+    time.sleep(1)
+
+    # Kill any existing process of this app
+    adb_utils.pkill(self.app_runner.package)
+
+    # Remove existing trace and compiler files
+    self.purge_file(PerfettoTraceCollector.TRACE_FILE_SUFFIX)
+
+    # Set perfetto trace duration prop to milliseconds.
+    adb_utils.set_prop(PerfettoTraceCollector.TRACE_DURATION_PROP,
+                       int(self.trace_duration.total_seconds()*
+                           PerfettoTraceCollector.MS_PER_SEC))
+
+    if not iorapd_utils.stop_iorapd():
+      raise RuntimeError('Cannot stop iorapd!')
+
+    if not iorapd_utils.enable_iorapd_perfetto():
+      raise RuntimeError('Cannot enable perfetto!')
+
+    if not iorapd_utils.disable_iorapd_readahead():
+      raise RuntimeError('Cannot disable readahead!')
+
+    if not iorapd_utils.start_iorapd():
+      raise RuntimeError('Cannot start iorapd!')
+
+    # Drop all caches to get cold starts.
+    adb_utils.vm_drop_cache()
+
+  def postprocess(self, pre_launch_timestamp: str):
+    # Kill any existing process of this app
+    adb_utils.pkill(self.app_runner.package)
+
+    iorapd_utils.disable_iorapd_perfetto()
+
+    if self.save_destination_file_path is not None:
+      adb_utils.pull_file(self._get_remote_path(),
+                          self.save_destination_file_path)
+
+  def metrics_selector(self, am_start_output: str,
+                       pre_launch_timestamp: str) -> str:
+    """Parses the metric after app startup by reading from logcat in a blocking
+    manner until all metrics have been found".
+
+    Returns:
+      An empty string because the metric needs no further parsing.
+    """
+    if not self._wait_for_perfetto_trace(pre_launch_timestamp):
+      raise RuntimeError('Could not save perfetto app trace file!')
+
+    return ''
+
+  def _wait_for_perfetto_trace(self, pre_launch_timestamp) -> Optional[str]:
+    """ Waits for the perfetto trace being saved to file.
+
+    The string is in the format of r".*Perfetto TraceBuffer saved to file:
+    <file path>.*"
+
+    Returns:
+      the string what the program waits for. If the string doesn't show up,
+      return None.
+    """
+    pattern = re.compile(r'.*Perfetto TraceBuffer saved to file: {}.*'.
+                         format(self._get_remote_path()))
+
+    # The pre_launch_timestamp is longer than what the datetime can parse. Trim
+    # last three digits to make them align. For example:
+    # 2019-07-02 23:20:06.972674825999 -> 2019-07-02 23:20:06.972674825
+    assert len(pre_launch_timestamp) == len('2019-07-02 23:20:06.972674825')
+    timestamp = datetime.datetime.strptime(pre_launch_timestamp[:-3],
+                                           '%Y-%m-%d %H:%M:%S.%f')
+
+    # The timeout of perfetto trace is longer than the normal app run timeout.
+    timeout_dt = self.app_runner.timeout * PerfettoTraceCollector._COLLECTOR_TIMEOUT_MULTIPLIER
+    timeout_end = timestamp + datetime.timedelta(seconds=timeout_dt)
+
+    return logcat_utils.blocking_wait_for_logcat_pattern(timestamp,
+                                                         pattern,
+                                                         timeout_end)
+
+  def _get_remote_path(self):
+    # For example: android.music%2Fmusic.TopLevelActivity.perfetto_trace.pb
+    return iorapd_utils._iorapd_path_to_data_file(self.app_runner.package,
+                                                  self.app_runner.activity,
+                                                  PerfettoTraceCollector.TRACE_FILE_SUFFIX)
diff --git a/startop/scripts/app_startup/lib/perfetto_trace_collector_test.py b/startop/scripts/app_startup/lib/perfetto_trace_collector_test.py
new file mode 100644
index 0000000..8d94fc5
--- /dev/null
+++ b/startop/scripts/app_startup/lib/perfetto_trace_collector_test.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Unit tests for the data_frame.py script."""
+import os
+import sys
+from pathlib import Path
+from datetime import timedelta
+
+from mock import call, patch
+from perfetto_trace_collector import PerfettoTraceCollector
+
+sys.path.append(Path(os.path.realpath(__file__)).parents[2])
+from app_startup.lib.app_runner import AppRunner
+
+RUNNER = PerfettoTraceCollector(package='music',
+                                activity='MainActivity',
+                                compiler_filter=None,
+                                timeout=10,
+                                simulate=False,
+                                trace_duration = timedelta(milliseconds=1000),
+                                # No actual file will be created. Just to
+                                # check the command.
+                                save_destination_file_path='/tmp/trace.pb')
+
+def _mocked_run_shell_command(*args, **kwargs):
+  if args[0] == 'adb shell ps | grep "music" | awk \'{print $2;}\'':
+    return (True, '9999')
+  else:
+    return (True, '')
+
+@patch('lib.logcat_utils.blocking_wait_for_logcat_pattern')
+@patch('lib.cmd_utils.run_shell_command')
+def test_perfetto_trace_collector_preprocess(mock_run_shell_command,
+                                             mock_blocking_wait_for_logcat_pattern):
+  mock_run_shell_command.side_effect = _mocked_run_shell_command
+  mock_blocking_wait_for_logcat_pattern.return_value = "Succeed!"
+
+  RUNNER.preprocess()
+
+  calls = [call('adb root'),
+           call('adb shell "getenforce"'),
+           call('adb shell "setenforce 0"'),
+           call('adb shell "stop"'),
+           call('adb shell "start"'),
+           call('adb wait-for-device'),
+           call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+           call('adb shell "kill 9999"'),
+           call(
+               'adb shell "[[ -f \'/data/misc/iorapd/music%2FMainActivity.perfetto_trace.pb\' ]] '
+               '&& rm -f \'/data/misc/iorapd/music%2FMainActivity.perfetto_trace.pb\' || exit 0"'),
+           call('adb shell "setprop "iorapd.perfetto.trace_duration_ms" "1000""'),
+           call(
+               'bash -c "source {}; iorapd_stop"'.format(
+                   AppRunner.IORAP_COMMON_BASH_SCRIPT)),
+           call(
+               'bash -c "source {}; iorapd_perfetto_enable"'.format(
+                   AppRunner.IORAP_COMMON_BASH_SCRIPT)),
+           call(
+               'bash -c "source {}; iorapd_readahead_disable"'.format(
+                   AppRunner.IORAP_COMMON_BASH_SCRIPT)),
+           call(
+               'bash -c "source {}; iorapd_start"'.format(
+                   AppRunner.IORAP_COMMON_BASH_SCRIPT)),
+           call('adb shell "echo 3 > /proc/sys/vm/drop_caches"')]
+
+  mock_run_shell_command.assert_has_calls(calls)
+
+@patch('lib.logcat_utils.blocking_wait_for_logcat_pattern')
+@patch('lib.cmd_utils.run_shell_command')
+def test_perfetto_trace_collector_postprocess(mock_run_shell_command,
+                                              mock_blocking_wait_for_logcat_pattern):
+  mock_run_shell_command.side_effect = _mocked_run_shell_command
+  mock_blocking_wait_for_logcat_pattern.return_value = "Succeed!"
+
+  RUNNER.postprocess('2019-07-02 23:20:06.972674825')
+
+  calls = [call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+           call('adb shell "kill 9999"'),
+           call(
+               'bash -c "source {}; iorapd_perfetto_disable"'.format(
+                   AppRunner.IORAP_COMMON_BASH_SCRIPT)),
+           call('adb pull '
+                '"/data/misc/iorapd/music%2FMainActivity.perfetto_trace.pb" '
+                '"/tmp/trace.pb"')]
+
+  mock_run_shell_command.assert_has_calls(calls)
diff --git a/startop/scripts/app_startup/run_app_with_prefetch.py b/startop/scripts/app_startup/run_app_with_prefetch.py
index 464742d..2f1eff2 100644
--- a/startop/scripts/app_startup/run_app_with_prefetch.py
+++ b/startop/scripts/app_startup/run_app_with_prefetch.py
@@ -30,32 +30,146 @@
 import os
 import sys
 import time
-from typing import List, Tuple, Optional, NamedTuple
+from typing import List, Tuple, Optional
 
 # local imports
 import lib.adb_utils as adb_utils
+from lib.app_runner import AppRunner, AppRunnerListener
 
 # global variables
 DIR = os.path.abspath(os.path.dirname(__file__))
-IORAP_COMMON_BASH_SCRIPT = os.path.realpath(os.path.join(DIR,
-                                                         '../iorap/common'))
-APP_STARTUP_COMMON_BASH_SCRIPT = os.path.realpath(os.path.join(DIR,
-                                                               'lib/common'))
 
 sys.path.append(os.path.dirname(DIR))
 import lib.print_utils as print_utils
 import lib.cmd_utils as cmd_utils
 import iorap.lib.iorapd_utils as iorapd_utils
 
-RunCommandArgs = NamedTuple('RunCommandArgs',
-                            [('package', str),
-                             ('readahead', str),
-                             ('activity', Optional[str]),
-                             ('compiler_filter', Optional[str]),
-                             ('timeout', Optional[int]),
-                             ('debug', bool),
-                             ('simulate', bool),
-                             ('input', Optional[str])])
+class PrefetchAppRunner(AppRunnerListener):
+  def __init__(self,
+               package: str,
+               activity: Optional[str],
+               readahead: str,
+               compiler_filter: Optional[str],
+               timeout: Optional[int],
+               simulate: bool,
+               debug: bool,
+               input:Optional[str],
+               **kwargs):
+    self.app_runner = AppRunner(package,
+                                activity,
+                                compiler_filter,
+                                timeout,
+                                simulate)
+    self.app_runner.add_callbacks(self)
+
+    self.simulate = simulate
+    self.readahead = readahead
+    self.debug = debug
+    self.input = input
+    print_utils.DEBUG = self.debug
+    cmd_utils.SIMULATE = self.simulate
+
+
+  def run(self) -> Optional[List[Tuple[str]]]:
+    """Runs an app.
+
+    Returns:
+      A list of (metric, value) tuples.
+    """
+    return self.app_runner.run()
+
+  def preprocess(self):
+    passed = self.validate_options()
+    if not passed:
+      return
+
+    # Sets up adb environment.
+    adb_utils.root()
+    adb_utils.disable_selinux()
+    time.sleep(1)
+
+    # Kill any existing process of this app
+    adb_utils.pkill(self.app_runner.package)
+
+    if self.readahead != 'warm':
+      print_utils.debug_print('Drop caches for non-warm start.')
+      # Drop all caches to get cold starts.
+      adb_utils.vm_drop_cache()
+
+    if self.readahead != 'warm' and self.readahead != 'cold':
+      iorapd_utils.enable_iorapd_readahead()
+
+  def postprocess(self, pre_launch_timestamp: str):
+    passed = self._perform_post_launch_cleanup(pre_launch_timestamp)
+    if not passed and not self.app_runner.simulate:
+      print_utils.error_print('Cannot perform post launch cleanup!')
+      return None
+
+    # Kill any existing process of this app
+    adb_utils.pkill(self.app_runner.package)
+
+  def _perform_post_launch_cleanup(self, logcat_timestamp: str) -> bool:
+    """Performs cleanup at the end of each loop iteration.
+
+    Returns:
+      A bool indicates whether the cleanup succeeds or not.
+    """
+    if self.readahead != 'warm' and self.readahead != 'cold':
+      passed = iorapd_utils.wait_for_iorapd_finish(self.app_runner.package,
+                                                   self.app_runner.activity,
+                                                   self.app_runner.timeout,
+                                                   self.debug,
+                                                   logcat_timestamp)
+
+      if not passed:
+        return passed
+
+      return iorapd_utils.disable_iorapd_readahead()
+
+    # Don't need to do anything for warm or cold.
+    return True
+
+  def metrics_selector(self, am_start_output: str,
+                       pre_launch_timestamp: str) -> str:
+    """Parses the metric after app startup by reading from logcat in a blocking
+    manner until all metrics have been found".
+
+    Returns:
+      the total time and displayed time of app startup.
+      For example: "TotalTime=123\nDisplayedTime=121
+    """
+    total_time = AppRunner.parse_total_time(am_start_output)
+    displayed_time = adb_utils.blocking_wait_for_logcat_displayed_time(
+        pre_launch_timestamp, self.app_runner.package, self.app_runner.timeout)
+
+    return 'TotalTime={}\nDisplayedTime={}'.format(total_time, displayed_time)
+
+  def validate_options(self) -> bool:
+    """Validates the activity and trace file if needed.
+
+    Returns:
+      A bool indicates whether the activity is valid.
+    """
+    needs_trace_file = self.readahead != 'cold' and self.readahead != 'warm'
+    if needs_trace_file and (self.input is None or
+                             not os.path.exists(self.input)):
+      print_utils.error_print('--input not specified!')
+      return False
+
+    # Install necessary trace file. This must be after the activity checking.
+    if needs_trace_file:
+      passed = iorapd_utils.iorapd_compiler_install_trace_file(
+          self.app_runner.package, self.app_runner.activity, self.input)
+      if not cmd_utils.SIMULATE and not passed:
+        print_utils.error_print('Failed to install compiled TraceFile.pb for '
+                                '"{}/{}"'.
+                                    format(self.app_runner.package,
+                                           self.app_runner.activity))
+        return False
+
+    return True
+
+
 
 def parse_options(argv: List[str] = None):
   """Parses command line arguments and return an argparse Namespace object."""
@@ -101,271 +215,10 @@
 
   return parser.parse_args(argv)
 
-def validate_options(args: RunCommandArgs) -> Tuple[bool, RunCommandArgs]:
-  """Validates the activity and trace file if needed.
-
-  Returns:
-    A bool indicates whether the activity is valid and trace file exists if
-    necessary.
-  """
-  needs_trace_file = (args.readahead != 'cold' and args.readahead != 'warm')
-  if needs_trace_file and (args.input is None or
-                           not os.path.exists(args.input)):
-    print_utils.error_print('--input not specified!')
-    return False, args
-
-  if args.simulate:
-    args = args._replace(activity='act')
-
-  if not args.activity:
-    _, activity = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
-                                           'get_activity_name',
-                                           [args.package])
-    args = args._replace(activity=activity)
-
-  if not args.activity:
-    print_utils.error_print('Activity name could not be found, '
-                            'invalid package name?!')
-    return False, args
-
-  # Install necessary trace file. This must be after the activity checking.
-  if needs_trace_file:
-    passed = iorapd_utils.iorapd_compiler_install_trace_file(
-        args.package, args.activity, args.input)
-    if not cmd_utils.SIMULATE and not passed:
-      print_utils.error_print('Failed to install compiled TraceFile.pb for '
-                              '"{}/{}"'.
-                                format(args.package, args.activity))
-      return False, args
-
-  return True, args
-
-def set_up_adb_env():
-  """Sets up adb environment."""
-  adb_utils.root()
-  adb_utils.disable_selinux()
-  time.sleep(1)
-
-def configure_compiler_filter(compiler_filter: str, package: str,
-                              activity: str) -> bool:
-  """Configures compiler filter (e.g. speed).
-
-  Returns:
-    A bool indicates whether configure of compiler filer succeeds or not.
-  """
-  if not compiler_filter:
-    print_utils.debug_print('No --compiler-filter specified, don\'t'
-                            ' need to force it.')
-    return True
-
-  passed, current_compiler_filter_info = \
-    cmd_utils.run_shell_command(
-        '{} --package {}'.format(os.path.join(DIR, 'query_compiler_filter.py'),
-                                 package))
-
-  if passed != 0:
-    return passed
-
-  # TODO: call query_compiler_filter directly as a python function instead of
-  #  these shell calls.
-  current_compiler_filter, current_reason, current_isa = \
-    current_compiler_filter_info.split(' ')
-  print_utils.debug_print('Compiler Filter={} Reason={} Isa={}'.format(
-      current_compiler_filter, current_reason, current_isa))
-
-  # Don't trust reasons that aren't 'unknown' because that means
-  #  we didn't manually force the compilation filter.
-  # (e.g. if any automatic system-triggered compilations are not unknown).
-  if current_reason != 'unknown' or current_compiler_filter != compiler_filter:
-    passed, _ = adb_utils.run_shell_command('{}/force_compiler_filter '
-                                            '--compiler-filter "{}" '
-                                            '--package "{}"'
-                                            ' --activity "{}'.
-                                              format(DIR, compiler_filter,
-                                                     package, activity))
-  else:
-    adb_utils.debug_print('Queried compiler-filter matched requested '
-                          'compiler-filter, skip forcing.')
-    passed = False
-  return passed
-
-def parse_metrics_output(input: str,
-                         simulate: bool = False) -> List[Tuple[str, str, str]]:
-  """Parses ouput of app startup to metrics and corresponding values.
-
-  It converts 'a=b\nc=d\ne=f\n...' into '[(a,b,''),(c,d,''),(e,f,'')]'
-
-  Returns:
-    A list of tuples that including metric name, metric value and rest info.
-  """
-  all_metrics = []
-  for line in input.split('\n'):
-    if not line:
-      continue
-    splits = line.split('=')
-    if len(splits) < 2:
-      print_utils.error_print('Bad line "{}"'.format(line))
-      continue
-    metric_name = splits[0]
-    metric_value = splits[1]
-    rest = splits[2] if len(splits) > 2 else ''
-    if rest:
-      print_utils.error_print('Corrupt line "{}"'.format(line))
-    print_utils.debug_print('metric: "{metric_name}", '
-                            'value: "{metric_value}" '.
-                              format(metric_name=metric_name,
-                                   metric_value=metric_value))
-
-    all_metrics.append((metric_name, metric_value))
-  return all_metrics
-
-def _parse_total_time(am_start_output: str) -> Optional[str]:
-  """Parses the total time from 'adb shell am start pkg' output.
-
-  Returns:
-    the total time of app startup.
-  """
-  for line in am_start_output.split('\n'):
-    if 'TotalTime:' in line:
-      return line[len('TotalTime:'):].strip()
-  return None
-
-def blocking_parse_all_metrics(am_start_output: str, package: str,
-                               pre_launch_timestamp: str,
-                               timeout: int) -> str:
-  """Parses the metric after app startup by reading from logcat in a blocking
-  manner until all metrics have been found".
-
-  Returns:
-    the total time and displayed time of app startup.
-    For example: "TotalTime=123\nDisplayedTime=121
-  """
-  total_time = _parse_total_time(am_start_output)
-  displayed_time = adb_utils.blocking_wait_for_logcat_displayed_time(
-      pre_launch_timestamp, package, timeout)
-
-  return 'TotalTime={}\nDisplayedTime={}'.format(total_time, displayed_time)
-
-def run(readahead: str,
-        package: str,
-        activity: str,
-        timeout: int,
-        simulate: bool,
-        debug: bool) -> List[Tuple[str, str]]:
-  """Runs app startup test.
-
-  Returns:
-    A list of tuples that including metric name, metric value and rest info.
-  """
-  print_utils.debug_print('==========================================')
-  print_utils.debug_print('=====             START              =====')
-  print_utils.debug_print('==========================================')
-
-  # Kill any existing process of this app
-  adb_utils.pkill(package)
-
-  if readahead != 'warm':
-    print_utils.debug_print('Drop caches for non-warm start.')
-    # Drop all caches to get cold starts.
-    adb_utils.vm_drop_cache()
-
-  if readahead != 'warm' and readahead != 'cold':
-    iorapd_utils.enable_iorapd_readahead()
-
-  print_utils.debug_print('Running with timeout {}'.format(timeout))
-
-  pre_launch_timestamp = adb_utils.logcat_save_timestamp()
-
-  passed, output = cmd_utils.run_shell_command('timeout {timeout} '
-                                               '"{DIR}/launch_application" '
-                                               '"{package}" '
-                                               '"{activity}"'
-                                                 .format(timeout=timeout,
-                                                       DIR=DIR,
-                                                       package=package,
-                                                       activity=activity))
-  if not passed and not simulate:
-    return None
-
-  if simulate:
-    results = [('TotalTime', '123')]
-  else:
-    output = blocking_parse_all_metrics(output,
-                                        package,
-                                        pre_launch_timestamp,
-                                        timeout)
-    results = parse_metrics_output(output, simulate)
-
-  passed = perform_post_launch_cleanup(
-      readahead, package, activity, timeout, debug, pre_launch_timestamp)
-  if not passed and not simulate:
-    print_utils.error_print('Cannot perform post launch cleanup!')
-    return None
-
-  adb_utils.pkill(package)
-  return results
-
-def perform_post_launch_cleanup(readahead: str,
-                                package: str,
-                                activity: str,
-                                timeout: int,
-                                debug: bool,
-                                logcat_timestamp: str) -> bool:
-  """Performs cleanup at the end of each loop iteration.
-
-  Returns:
-    A bool indicates whether the cleanup succeeds or not.
-  """
-  if readahead != 'warm' and readahead != 'cold':
-    passed = iorapd_utils.wait_for_iorapd_finish(package,
-                                                 activity,
-                                                 timeout,
-                                                 debug,
-                                                 logcat_timestamp)
-
-    if not passed:
-      return passed
-
-    return iorapd_utils.disable_iorapd_readahead()
-
-  # Don't need to do anything for warm or cold.
-  return True
-
-def run_test(args: RunCommandArgs) -> List[Tuple[str, str]]:
-  """Runs one test using given options.
-
-  Returns:
-    A list of tuples that including metric name, metric value.
-  """
-  print_utils.DEBUG = args.debug
-  cmd_utils.SIMULATE = args.simulate
-
-  passed, args = validate_options(args)
-  if not passed:
-    return None
-
-  set_up_adb_env()
-
-  # Ensure the APK is currently compiled with whatever we passed in
-  # via --compiler-filter.
-  # No-op if this option was not passed in.
-  if not configure_compiler_filter(args.compiler_filter, args.package,
-                                   args.activity):
-    return None
-
-  return run(args.readahead, args.package, args.activity, args.timeout,
-             args.simulate, args.debug)
-
-def get_args_from_opts(opts: argparse.Namespace) -> RunCommandArgs:
-  kwargs = {}
-  for field in RunCommandArgs._fields:
-    kwargs[field] = getattr(opts, field)
-  return RunCommandArgs(**kwargs)
-
 def main():
   opts = parse_options()
-  args = get_args_from_opts(opts)
-  result = run_test(args)
+  runner = PrefetchAppRunner(**vars(opts))
+  result = runner.run()
 
   if result is None:
     return 1
diff --git a/startop/scripts/app_startup/run_app_with_prefetch_test.py b/startop/scripts/app_startup/run_app_with_prefetch_test.py
index 8536ce5..8a588e4 100644
--- a/startop/scripts/app_startup/run_app_with_prefetch_test.py
+++ b/startop/scripts/app_startup/run_app_with_prefetch_test.py
@@ -33,17 +33,18 @@
 import os
 import shlex
 import sys
+import tempfile
 # global imports
 from contextlib import contextmanager
 
 # pip imports
 import pytest
 # local imports
-import run_app_with_prefetch as run
-from mock import Mock, call, patch
+import run_app_with_prefetch as runner
+from mock import call, patch, Mock
 
 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
+from app_startup.lib.app_runner import AppRunner
 #
 # Argument Parsing Helpers
 #
@@ -85,7 +86,7 @@
     :return:  dictionary of parsed key/values
     """
   # "-a b -c d"    => ['-a', 'b', '-c', 'd']
-  return vars(run.parse_options(shlex.split(args)))
+  return vars(runner.parse_options(shlex.split(args)))
 
 def default_dict_for_parsed_args(**kwargs):
   """Combines it with all of the "optional" parameters' default values."""
@@ -154,130 +155,132 @@
 
 def test_main():
   args = '--package com.fake.package --activity act -s'
-  opts = run.parse_options(shlex.split(args))
-
-  args = run.get_args_from_opts(opts)
-  result = run.run_test(args)
+  opts = runner.parse_options(shlex.split(args))
+  result = runner.PrefetchAppRunner(**vars(opts)).run()
   assert result == [('TotalTime', '123')]
 
-def test_set_up_adb_env():
+def _mocked_run_shell_command(*args, **kwargs):
+  if args[0] == 'adb shell ps | grep "music" | awk \'{print $2;}\'':
+    return (True, '9999')
+  else:
+    return (True, '')
+
+def test_preprocess_no_cache_drop():
   with patch('lib.cmd_utils.run_shell_command',
              new_callable=Mock) as mock_run_shell_command:
-    mock_run_shell_command.return_value = (True, '')
-    run.set_up_adb_env()
+    mock_run_shell_command.side_effect = _mocked_run_shell_command
+    prefetch_app_runner = runner.PrefetchAppRunner(package='music',
+                                                   activity='MainActivity',
+                                                   readahead='warm',
+                                                   compiler_filter=None,
+                                                   timeout=None,
+                                                   simulate=False,
+                                                   debug=False,
+                                                   input=None)
+
+    prefetch_app_runner.preprocess()
 
     calls = [call('adb root'),
              call('adb shell "getenforce"'),
              call('adb shell "setenforce 0"'),
              call('adb shell "stop"'),
              call('adb shell "start"'),
-             call('adb wait-for-device')]
+             call('adb wait-for-device'),
+             call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+             call('adb shell "kill 9999"')]
     mock_run_shell_command.assert_has_calls(calls)
 
-def test_set_up_adb_env_with_permissive():
+def test_preprocess_with_cache_drop():
   with patch('lib.cmd_utils.run_shell_command',
              new_callable=Mock) as mock_run_shell_command:
-    mock_run_shell_command.return_value = (True, 'Permissive')
-    run.set_up_adb_env()
+    mock_run_shell_command.side_effect = _mocked_run_shell_command
+    prefetch_app_runner = runner.PrefetchAppRunner(package='music',
+                                                   activity='MainActivity',
+                                                   readahead='cold',
+                                                   compiler_filter=None,
+                                                   timeout=None,
+                                                   simulate=False,
+                                                   debug=False,
+                                                   input=None)
 
-    calls = [call('adb root'), call('adb shell "getenforce"')]
+    prefetch_app_runner.preprocess()
+
+    calls = [call('adb root'),
+             call('adb shell "getenforce"'),
+             call('adb shell "setenforce 0"'),
+             call('adb shell "stop"'),
+             call('adb shell "start"'),
+             call('adb wait-for-device'),
+             call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+             call('adb shell "kill 9999"'),
+             call('adb shell "echo 3 > /proc/sys/vm/drop_caches"')]
     mock_run_shell_command.assert_has_calls(calls)
 
-def test_configure_compiler_filter():
+def test_preprocess_with_cache_drop_and_iorapd_enabled():
   with patch('lib.cmd_utils.run_shell_command',
              new_callable=Mock) as mock_run_shell_command:
-    mock_run_shell_command.return_value = (True, 'speed arm64 kUpToDate')
-    run.configure_compiler_filter('speed', 'music', 'MainActivity')
+    mock_run_shell_command.side_effect = _mocked_run_shell_command
 
-    calls = [call(os.path.join(run.DIR, 'query_compiler_filter.py') +
-                  ' --package music')]
-    mock_run_shell_command.assert_has_calls(calls)
+    with tempfile.NamedTemporaryFile() as input:
+      prefetch_app_runner = runner.PrefetchAppRunner(package='music',
+                                                     activity='MainActivity',
+                                                     readahead='fadvise',
+                                                     compiler_filter=None,
+                                                     timeout=None,
+                                                     simulate=False,
+                                                     debug=False,
+                                                     input=input.name)
 
-def test_parse_metrics_output():
-  input = 'a1=b1\nc1=d1\ne1=f1'
-  ret = run.parse_metrics_output(input)
+      prefetch_app_runner.preprocess()
 
-  assert ret == [('a1', 'b1'), ('c1', 'd1'), ('e1', 'f1')]
-
-def _mocked_run_shell_command(*args, **kwargs):
-  if args[0] == 'adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"':
-    return (True, "2019-07-02 23:20:06.972674825")
-  elif args[0] == 'adb shell ps | grep "music" | awk \'{print $2;}\'':
-    return (True, '9999')
-  else:
-    return (True, 'a1=b1\nc1=d1=d2\ne1=f1')
+      calls = [call('adb root'),
+               call('adb shell "getenforce"'),
+               call('adb shell "setenforce 0"'),
+               call('adb shell "stop"'),
+               call('adb shell "start"'),
+               call('adb wait-for-device'),
+               call(
+                   'adb shell ps | grep "music" | awk \'{print $2;}\''),
+               call('adb shell "kill 9999"'),
+               call('adb shell "echo 3 > /proc/sys/vm/drop_caches"'),
+               call('bash -c "source {}; iorapd_readahead_enable"'.
+                    format(AppRunner.IORAP_COMMON_BASH_SCRIPT))]
+      mock_run_shell_command.assert_has_calls(calls)
 
 @patch('lib.adb_utils.blocking_wait_for_logcat_displayed_time')
 @patch('lib.cmd_utils.run_shell_command')
-def test_run_no_vm_cache_drop(mock_run_shell_command,
-                              mock_blocking_wait_for_logcat_displayed_time):
-  mock_run_shell_command.side_effect = _mocked_run_shell_command
-  mock_blocking_wait_for_logcat_displayed_time.return_value = 123
-
-  run.run('warm',
-          'music',
-          'MainActivity',
-          timeout=10,
-          simulate=False,
-          debug=False)
-
-  calls = [call('adb shell ps | grep "music" | awk \'{print $2;}\''),
-           call('adb shell "kill 9999"'),
-           call('adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"'),
-           call(
-             'timeout {timeout} "{DIR}/launch_application" "{package}" "{activity}"'
-               .format(timeout=10,
-                       DIR=run.DIR,
-                       package='music',
-                       activity='MainActivity',
-                       timestamp='2019-07-02 23:20:06.972674825')),
-           call('adb shell ps | grep "music" | awk \'{print $2;}\''),
-           call('adb shell "kill 9999"')]
-  mock_run_shell_command.assert_has_calls(calls)
-
-@patch('lib.adb_utils.blocking_wait_for_logcat_displayed_time')
-@patch('lib.cmd_utils.run_shell_command')
-def test_run_with_vm_cache_drop_and_post_launch_cleanup(
+def test_postprocess_with_launch_cleanup(
     mock_run_shell_command,
     mock_blocking_wait_for_logcat_displayed_time):
   mock_run_shell_command.side_effect = _mocked_run_shell_command
   mock_blocking_wait_for_logcat_displayed_time.return_value = 123
 
-  run.run('fadvise',
-          'music',
-          'MainActivity',
-          timeout=10,
-          simulate=False,
-          debug=False)
+  with tempfile.NamedTemporaryFile() as input:
+    prefetch_app_runner = runner.PrefetchAppRunner(package='music',
+                                                   activity='MainActivity',
+                                                   readahead='fadvise',
+                                                   compiler_filter=None,
+                                                   timeout=10,
+                                                   simulate=False,
+                                                   debug=False,
+                                                   input=input.name)
 
-  calls = [call('adb shell ps | grep "music" | awk \'{print $2;}\''),
-           call('adb shell "kill 9999"'),
-           call('adb shell "echo 3 > /proc/sys/vm/drop_caches"'),
-           call('bash -c "source {}; iorapd_readahead_enable"'.
-                format(run.IORAP_COMMON_BASH_SCRIPT)),
-           call('adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"'),
-           call(
-             'timeout {timeout} "{DIR}/launch_application" '
-             '"{package}" "{activity}"'
-               .format(timeout=10,
-                       DIR=run.DIR,
-                       package='music',
-                       activity='MainActivity',
-                       timestamp='2019-07-02 23:20:06.972674825')),
-           call(
-             'bash -c "source {script_path}; '
+    prefetch_app_runner.postprocess('2019-07-02 23:20:06.972674825')
+
+    calls = [
+        call('bash -c "source {script_path}; '
              'iorapd_readahead_wait_until_finished '
              '\'{package}\' \'{activity}\' \'{timestamp}\' \'{timeout}\'"'.
-               format(timeout=10,
-                      package='music',
-                      activity='MainActivity',
-                      timestamp='2019-07-02 23:20:06.972674825',
-                      script_path=run.IORAP_COMMON_BASH_SCRIPT)),
-           call('bash -c "source {}; iorapd_readahead_disable"'.
-                format(run.IORAP_COMMON_BASH_SCRIPT)),
-           call('adb shell ps | grep "music" | awk \'{print $2;}\''),
-           call('adb shell "kill 9999"')]
-  mock_run_shell_command.assert_has_calls(calls)
+                 format(timeout=10,
+                        package='music',
+                        activity='MainActivity',
+                        timestamp='2019-07-02 23:20:06.972674825',
+                        script_path=AppRunner.IORAP_COMMON_BASH_SCRIPT)),
+        call('bash -c "source {}; iorapd_readahead_disable"'.
+             format(AppRunner.IORAP_COMMON_BASH_SCRIPT)),
+        call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+        call('adb shell "kill 9999"')]
+    mock_run_shell_command.assert_has_calls(calls)
 
 if __name__ == '__main__':
   pytest.main()
diff --git a/startop/scripts/iorap/compiler.py b/startop/scripts/iorap/compiler.py
index 9527e28..ef9b870 100755
--- a/startop/scripts/iorap/compiler.py
+++ b/startop/scripts/iorap/compiler.py
@@ -31,8 +31,10 @@
 from pathlib import Path
 from typing import Iterable, Optional, List
 
-from generated.TraceFile_pb2 import *
-from lib.inode2filename import Inode2Filename
+DIR = os.path.abspath(os.path.dirname(__file__))
+sys.path.append(os.path.dirname(DIR))
+from iorap.generated.TraceFile_pb2 import *
+from iorap.lib.inode2filename import Inode2Filename
 
 parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
 sys.path.append(parent_dir_name)
diff --git a/startop/scripts/iorap/lib/iorapd_utils.py b/startop/scripts/iorap/lib/iorapd_utils.py
index c03e9b0..0d62180 100644
--- a/startop/scripts/iorap/lib/iorapd_utils.py
+++ b/startop/scripts/iorap/lib/iorapd_utils.py
@@ -111,3 +111,50 @@
   passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
                                        'iorapd_readahead_disable', [])
   return passed
+
+def enable_iorapd_perfetto() -> bool:
+  """
+  Enable Perfetto. Subsequent launches of an application will record a perfetto
+  trace protobuf.
+
+  Returns:
+    A bool indicates whether the enabling is done successfully or not.
+  """
+  passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
+                                       'iorapd_perfetto_enable', [])
+  return passed
+
+def disable_iorapd_perfetto() -> bool:
+  """
+  Disable Perfetto. Subsequent launches of applications will no longer record
+  perfetto trace protobufs.
+
+  Returns:
+    A bool indicates whether the disabling is done successfully or not.
+  """
+  passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
+                                       'iorapd_perfetto_disable', [])
+  return passed
+
+def start_iorapd() -> bool:
+  """
+  Starts iorapd.
+
+  Returns:
+    A bool indicates whether the starting is done successfully or not.
+  """
+  passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
+                                       'iorapd_start', [])
+  return passed
+
+def stop_iorapd() -> bool:
+  """
+  Stops iorapd.
+
+  Returns:
+    A bool indicates whether the stopping is done successfully or not.
+  """
+  passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
+                                       'iorapd_stop', [])
+  return passed
+
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 09f9c04..499c42e 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -108,6 +108,12 @@
     case Instruction::Op::kSetStaticField:
       out << "kSetStaticField";
       return out;
+    case Instruction::Op::kGetInstanceField:
+      out << "kGetInstanceField";
+      return out;
+    case Instruction::Op::kSetInstanceField:
+      out << "kSetInstanceField";
+      return out;
   }
 }
 
@@ -246,6 +252,7 @@
   field->parent = GetOrAddType(parent);
   field->name = GetOrAddString(name);
   field->type = GetOrAddType(type);
+  field->orig_index = dex_file_->fields_indexes.AllocateIndex();
   dex_file_->fields_map[field->orig_index] = field;
   field_decls_by_key_[key] = field;
   return field;
@@ -384,7 +391,9 @@
       return EncodeCast(instruction);
     case Instruction::Op::kGetStaticField:
     case Instruction::Op::kSetStaticField:
-      return EncodeStaticFieldOp(instruction);
+    case Instruction::Op::kGetInstanceField:
+    case Instruction::Op::kSetInstanceField:
+      return EncodeFieldOp(instruction);
   }
 }
 
@@ -539,7 +548,8 @@
   Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
 }
 
-void MethodBuilder::EncodeStaticFieldOp(const Instruction& instruction) {
+void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
+  const auto& args = instruction.args();
   switch (instruction.opcode()) {
     case Instruction::Op::kGetStaticField: {
       CHECK(instruction.dest().has_value());
@@ -553,18 +563,36 @@
     }
     case Instruction::Op::kSetStaticField: {
       CHECK(!instruction.dest().has_value());
-      const auto& args = instruction.args();
       CHECK_EQ(1, args.size());
       CHECK(args[0].is_variable());
 
-      Encode21c(::art::Instruction::SPUT,
+      Encode21c(::art::Instruction::SPUT, RegisterValue(args[0]), instruction.index_argument());
+      break;
+    }
+    case Instruction::Op::kGetInstanceField: {
+      CHECK(instruction.dest().has_value());
+      CHECK(instruction.dest()->is_variable());
+      CHECK_EQ(1, instruction.args().size());
+
+      Encode22c(::art::Instruction::IGET,
+                RegisterValue(*instruction.dest()),
                 RegisterValue(args[0]),
                 instruction.index_argument());
       break;
     }
-    default: {
-      LOG(FATAL) << "Unsupported static field operation";
+    case Instruction::Op::kSetInstanceField: {
+      CHECK(!instruction.dest().has_value());
+      CHECK_EQ(2, args.size());
+      CHECK(args[0].is_variable());
+      CHECK(args[1].is_variable());
+
+      Encode22c(::art::Instruction::IPUT,
+                RegisterValue(args[1]),
+                RegisterValue(args[0]),
+                instruction.index_argument());
+      break;
     }
+    default: { LOG(FATAL) << "Unsupported field operation"; }
   }
 }
 
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index 3f9ac43..292d659 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -153,6 +153,7 @@
     kBranchEqz,
     kBranchNEqz,
     kCheckCast,
+    kGetInstanceField,
     kGetStaticField,
     kInvokeDirect,
     kInvokeInterface,
@@ -163,6 +164,7 @@
     kNew,
     kReturn,
     kReturnObject,
+    kSetInstanceField,
     kSetStaticField
   };
 
@@ -195,8 +197,9 @@
   }
   // Returns an object
   template <typename... T>
-  static inline Instruction InvokeVirtualObject(size_t index_argument, std::optional<const Value> dest,
-                                                Value this_arg, T... args) {
+  static inline Instruction InvokeVirtualObject(size_t index_argument,
+                                                std::optional<const Value> dest, Value this_arg,
+                                                T... args) {
     return Instruction{
         Op::kInvokeVirtual, index_argument, /*result_is_object=*/true, dest, this_arg, args...};
   }
@@ -209,8 +212,9 @@
   }
   // Returns an object
   template <typename... T>
-  static inline Instruction InvokeDirectObject(size_t index_argument, std::optional<const Value> dest,
-                                               Value this_arg, T... args) {
+  static inline Instruction InvokeDirectObject(size_t index_argument,
+                                               std::optional<const Value> dest, Value this_arg,
+                                               T... args) {
     return Instruction{
         Op::kInvokeDirect, index_argument, /*result_is_object=*/true, dest, this_arg, args...};
   }
@@ -218,20 +222,21 @@
   template <typename... T>
   static inline Instruction InvokeStatic(size_t index_argument, std::optional<const Value> dest,
                                          T... args) {
-    return Instruction{Op::kInvokeStatic, index_argument, /*result_is_object=*/false, dest, args...};
+    return Instruction{
+        Op::kInvokeStatic, index_argument, /*result_is_object=*/false, dest, args...};
   }
   // Returns an object
   template <typename... T>
-  static inline Instruction InvokeStaticObject(size_t index_argument, std::optional<const Value> dest,
-                                               T... args) {
+  static inline Instruction InvokeStaticObject(size_t index_argument,
+                                               std::optional<const Value> dest, T... args) {
     return Instruction{Op::kInvokeStatic, index_argument, /*result_is_object=*/true, dest, args...};
   }
   // For static calls.
   template <typename... T>
   static inline Instruction InvokeInterface(size_t index_argument, std::optional<const Value> dest,
                                             T... args) {
-    return Instruction{Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...};
-
+    return Instruction{
+        Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...};
   }
 
   static inline Instruction GetStaticField(size_t field_id, Value dest) {
@@ -239,9 +244,18 @@
   }
 
   static inline Instruction SetStaticField(size_t field_id, Value value) {
-    return Instruction{Op::kSetStaticField, field_id, /*result_is_object=*/false, /*dest=*/{}, value};
+    return Instruction{
+        Op::kSetStaticField, field_id, /*result_is_object=*/false, /*dest=*/{}, value};
   }
 
+  static inline Instruction GetField(size_t field_id, Value dest, Value object) {
+    return Instruction{Op::kGetInstanceField, field_id, /*result_is_object=*/false, dest, object};
+  }
+
+  static inline Instruction SetField(size_t field_id, Value object, Value value) {
+    return Instruction{
+        Op::kSetInstanceField, field_id, /*result_is_object=*/false, /*dest=*/{}, object, value};
+  }
 
   ///////////////
   // Accessors //
@@ -255,10 +269,14 @@
 
  private:
   inline Instruction(Op opcode, size_t index_argument, std::optional<const Value> dest)
-      : opcode_{opcode}, index_argument_{index_argument}, result_is_object_{false}, dest_{dest}, args_{} {}
+      : opcode_{opcode},
+        index_argument_{index_argument},
+        result_is_object_{false},
+        dest_{dest},
+        args_{} {}
 
   template <typename... T>
-  inline constexpr Instruction(Op opcode, size_t index_argument, bool result_is_object,
+  inline Instruction(Op opcode, size_t index_argument, bool result_is_object,
                                std::optional<const Value> dest, T... args)
       : opcode_{opcode},
         index_argument_{index_argument},
@@ -331,7 +349,7 @@
   void EncodeBranch(art::Instruction::Code op, const Instruction& instruction);
   void EncodeNew(const Instruction& instruction);
   void EncodeCast(const Instruction& instruction);
-  void EncodeStaticFieldOp(const Instruction& instruction);
+  void EncodeFieldOp(const Instruction& instruction);
 
   // Low-level instruction format encoding. See
   // https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of
@@ -364,6 +382,14 @@
     buffer_.push_back(b);
   }
 
+  inline void Encode22c(art::Instruction::Code opcode, uint8_t a, uint8_t b, uint16_t c) {
+    // b|a|op|bbbb
+    CHECK(IsShortRegister(a));
+    CHECK(IsShortRegister(b));
+    buffer_.push_back((b << 12) | (a << 8) | opcode);
+    buffer_.push_back(c);
+  }
+
   inline void Encode32x(art::Instruction::Code opcode, uint16_t a, uint16_t b) {
     buffer_.push_back(opcode);
     buffer_.push_back(a);
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
index 6c0b8bb..d1fe588 100644
--- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
@@ -186,4 +186,25 @@
     method.invoke(null);
     Assert.assertEquals(7, TestClass.staticInteger);
   }
+
+  @Test
+  public void readInstanceField() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("readInstanceField", TestClass.class);
+    TestClass obj = new TestClass();
+    obj.instanceField = 5;
+    Assert.assertEquals(5, method.invoke(null, obj));
+  }
+
+  @Test
+  public void setInstanceField() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("setInstanceField", TestClass.class);
+    TestClass obj = new TestClass();
+    obj.instanceField = 5;
+    method.invoke(null, obj);
+    Assert.assertEquals(7, obj.instanceField);
+  }
 }
diff --git a/startop/view_compiler/dex_layout_compiler.cc b/startop/view_compiler/dex_layout_compiler.cc
index c68793d..8febfb7 100644
--- a/startop/view_compiler/dex_layout_compiler.cc
+++ b/startop/view_compiler/dex_layout_compiler.cc
@@ -23,25 +23,6 @@
 
 using android::base::StringPrintf;
 
-void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) {
-  if (0 == name.compare(u"merge")) {
-    message_ = "Merge tags are not supported";
-    can_compile_ = false;
-  }
-  if (0 == name.compare(u"include")) {
-    message_ = "Include tags are not supported";
-    can_compile_ = false;
-  }
-  if (0 == name.compare(u"view")) {
-    message_ = "View tags are not supported";
-    can_compile_ = false;
-  }
-  if (0 == name.compare(u"fragment")) {
-    message_ = "Fragment tags are not supported";
-    can_compile_ = false;
-  }
-}
-
 DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method)
     : method_{method},
       context_{dex::Value::Parameter(0)},
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc
index fee5e72..6dedf24 100644
--- a/startop/view_compiler/dex_testcase_generator.cc
+++ b/startop/view_compiler/dex_testcase_generator.cc
@@ -282,15 +282,15 @@
     method.Encode();
   }(castObjectToString);
 
+  TypeDescriptor test_class = TypeDescriptor::FromClassname("android.startop.test.TestClass");
+
   // Read a static field
-  // integer readStaticField() { return TestClass.staticInteger; }
+  // int readStaticField() { return TestClass.staticInteger; }
   MethodBuilder readStaticField{
       cbuilder.CreateMethod("readStaticField", Prototype{TypeDescriptor::Int()})};
   [&](MethodBuilder& method) {
     const ir::FieldDecl* field =
-        dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"),
-                               "staticInteger",
-                               TypeDescriptor::Int());
+        dex_file.GetOrAddField(test_class, "staticInteger", TypeDescriptor::Int());
     Value result{method.MakeRegister()};
     method.AddInstruction(Instruction::GetStaticField(field->orig_index, result));
     method.BuildReturn(result, /*is_object=*/false);
@@ -303,9 +303,7 @@
       cbuilder.CreateMethod("setStaticField", Prototype{TypeDescriptor::Void()})};
   [&](MethodBuilder& method) {
     const ir::FieldDecl* field =
-        dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"),
-                               "staticInteger",
-                               TypeDescriptor::Int());
+        dex_file.GetOrAddField(test_class, "staticInteger", TypeDescriptor::Int());
     Value number{method.MakeRegister()};
     method.BuildConst4(number, 7);
     method.AddInstruction(Instruction::SetStaticField(field->orig_index, number));
@@ -313,6 +311,33 @@
     method.Encode();
   }(setStaticField);
 
+  // Read an instance field
+  // int readInstanceField(TestClass obj) { return obj.instanceField; }
+  MethodBuilder readInstanceField{
+      cbuilder.CreateMethod("readInstanceField", Prototype{TypeDescriptor::Int(), test_class})};
+  [&](MethodBuilder& method) {
+    const ir::FieldDecl* field =
+        dex_file.GetOrAddField(test_class, "instanceField", TypeDescriptor::Int());
+    Value result{method.MakeRegister()};
+    method.AddInstruction(Instruction::GetField(field->orig_index, result, Value::Parameter(0)));
+    method.BuildReturn(result, /*is_object=*/false);
+    method.Encode();
+  }(readInstanceField);
+
+  // Set an instance field
+  // void setInstanceField(TestClass obj) { obj.instanceField = 7; }
+  MethodBuilder setInstanceField{
+      cbuilder.CreateMethod("setInstanceField", Prototype{TypeDescriptor::Void(), test_class})};
+  [&](MethodBuilder& method) {
+    const ir::FieldDecl* field =
+        dex_file.GetOrAddField(test_class, "instanceField", TypeDescriptor::Int());
+    Value number{method.MakeRegister()};
+    method.BuildConst4(number, 7);
+    method.AddInstruction(Instruction::SetField(field->orig_index, Value::Parameter(0), number));
+    method.BuildReturn();
+    method.Encode();
+  }(setInstanceField);
+
   slicer::MemView image{dex_file.CreateImage()};
   std::ofstream out_file(outdir + "/simple.dex");
   out_file.write(image.ptr<const char>(), image.size());
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4016c5c..292a294 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2151,6 +2151,15 @@
             "data_warning_notification_bool";
 
     /**
+     * Controls if the device should automatically warn the user that sim voice & data function
+     * might be limited due to dual sim scenario. When set to {@true} display the notification,
+     * {@code false} otherwise.
+     * @hide
+     */
+    public static final String KEY_LIMITED_SIM_FUNCTION_NOTIFICATION_FOR_DSDS_BOOL =
+            "limited_sim_function_notification_for_dsds_bool";
+
+    /**
      * Controls the cellular data limit.
      * <p>
      * If the user uses more than this amount of data in their billing cycle, as defined by
@@ -2319,6 +2328,13 @@
     public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
 
     /**
+     * Indicates if the TTY HCO and VCO options should be hidden in the accessibility menu
+     * if the device is capable of RTT.
+     * @hide
+     */
+    public static final String KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL = "hide_tty_hco_vco_with_rtt";
+
+    /**
      * The flag to disable the popup dialog which warns the user of data charges.
      * @hide
      */
@@ -2398,6 +2414,14 @@
     public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL =
             "check_pricing_with_carrier_data_roaming_bool";
 
+     /**
+      * Determines whether we should show a notification when the phone established a data
+      * connection in roaming network, to warn users about possible roaming charges.
+      * @hide
+      */
+    public static final String KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL =
+            "show_data_connected_roaming_notification";
+
     /**
      * A list of 4 LTE RSRP thresholds above which a signal level is considered POOR,
      * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
@@ -2885,7 +2909,7 @@
             defaults.putString(KEY_SUPL_VER_STRING, "0x20000");
             defaults.putString(KEY_SUPL_MODE_STRING, "1");
             defaults.putString(KEY_SUPL_ES_STRING, "1");
-            defaults.putString(KEY_LPP_PROFILE_STRING, "0");
+            defaults.putString(KEY_LPP_PROFILE_STRING, "2");
             defaults.putString(KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING, "1");
             defaults.putString(KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, "0");
             defaults.putString(KEY_GPS_LOCK_STRING, "3");
@@ -3343,6 +3367,7 @@
         sDefaults.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, DATA_CYCLE_USE_PLATFORM_DEFAULT);
         sDefaults.putLong(KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, DATA_CYCLE_USE_PLATFORM_DEFAULT);
         sDefaults.putBoolean(KEY_DATA_WARNING_NOTIFICATION_BOOL, true);
+        sDefaults.putBoolean(KEY_LIMITED_SIM_FUNCTION_NOTIFICATION_FOR_DSDS_BOOL, false);
         sDefaults.putLong(KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, DATA_CYCLE_USE_PLATFORM_DEFAULT);
         sDefaults.putBoolean(KEY_DATA_LIMIT_NOTIFICATION_BOOL, true);
         sDefaults.putBoolean(KEY_DATA_RAPID_NOTIFICATION_BOOL, true);
@@ -3396,6 +3421,7 @@
         sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
+        sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
         sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
@@ -3414,6 +3440,7 @@
         sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING, "");
         sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
         sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
+        sDefaults.putBoolean(KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL, false);
         sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
                 new int[] {
                         -128, /* SIGNAL_STRENGTH_POOR */
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index cdf4c93..aa7e21a 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -340,6 +340,19 @@
      */
     public static final int MEDIA_TIMEOUT = 77;
 
+    /**
+     * Indicates that an emergency call cannot be placed over WFC because the service is not
+     * available in the current location.
+     * @hide
+     */
+    public static final int EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 78;
+
+    /**
+     * Indicates that WiFi calling service is not available in the current location.
+     * @hide
+     */
+    public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Update toString() with the newly added disconnect type.
@@ -510,6 +523,10 @@
             return "OTASP_PROVISIONING_IN_PROCESS";
         case MEDIA_TIMEOUT:
             return "MEDIA_TIMEOUT";
+        case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
+            return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
+        case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
+            return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index b75e515..f03a9dc 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -22,9 +22,11 @@
 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
 
 import android.annotation.IntDef;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.location.CountryDetector;
 import android.net.Uri;
@@ -164,6 +166,33 @@
         return c == 'w'||c == 'W';
     }
 
+    private static int sMinMatch = 0;
+
+    private static int getMinMatch() {
+        if (sMinMatch == 0) {
+            sMinMatch = Resources.getSystem().getInteger(
+                    com.android.internal.R.integer.config_phonenumber_compare_min_match);
+        }
+        return sMinMatch;
+    }
+
+    /**
+     * A Test API to get current sMinMatch.
+     * @hide
+     */
+    @TestApi
+    public static int getMinMatchForTest() {
+        return getMinMatch();
+    }
+
+    /**
+     * A Test API to set sMinMatch.
+     * @hide
+     */
+    @TestApi
+    public static void setMinMatchForTest(int minMatch) {
+        sMinMatch = minMatch;
+    }
 
     /** Returns true if ch is not dialable or alpha char */
     private static boolean isSeparator(char ch) {
@@ -475,7 +504,7 @@
      * enough for caller ID purposes.
      *
      * - Compares from right to left
-     * - requires MIN_MATCH (7) characters to match
+     * - requires minimum characters to match
      * - handles common trunk prefixes and international prefixes
      *   (basically, everything except the Russian trunk prefix)
      *
@@ -491,6 +520,7 @@
         int matched;
         int numNonDialableCharsInA = 0;
         int numNonDialableCharsInB = 0;
+        int minMatch = getMinMatch();
 
         if (a == null || b == null) return a == b;
 
@@ -530,12 +560,12 @@
             }
         }
 
-        if (matched < MIN_MATCH) {
+        if (matched < minMatch) {
             int effectiveALen = a.length() - numNonDialableCharsInA;
             int effectiveBLen = b.length() - numNonDialableCharsInB;
 
 
-            // if the number of dialable chars in a and b match, but the matched chars < MIN_MATCH,
+            // if the number of dialable chars in a and b match, but the matched chars < minMatch,
             // treat them as equal (i.e. 404-04 and 40404)
             if (effectiveALen == effectiveBLen && effectiveALen == matched) {
                 return true;
@@ -545,7 +575,7 @@
         }
 
         // At least one string has matched completely;
-        if (matched >= MIN_MATCH && (ia < 0 || ib < 0)) {
+        if (matched >= minMatch && (ia < 0 || ib < 0)) {
             return true;
         }
 
@@ -736,7 +766,7 @@
     }
 
     /**
-     * Returns the rightmost MIN_MATCH (5) characters in the network portion
+     * Returns the rightmost minimum matched characters in the network portion
      * in *reversed* order
      *
      * This can be used to do a database lookup against the column
@@ -747,7 +777,7 @@
     public static String
     toCallerIDMinMatch(String phoneNumber) {
         String np = extractNetworkPortionAlt(phoneNumber);
-        return internalGetStrippedReversed(np, MIN_MATCH);
+        return internalGetStrippedReversed(np, getMinMatch());
     }
 
     /**
@@ -1709,26 +1739,6 @@
         return normalizedDigits.toString();
     }
 
-    // Three and four digit phone numbers for either special services,
-    // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
-    // not match.
-    //
-    // This constant used to be 5, but SMS short codes has increased in length and
-    // can be easily 6 digits now days. Most countries have SMS short code length between
-    // 3 to 6 digits. The exceptions are
-    //
-    // Australia: Short codes are six or eight digits in length, starting with the prefix "19"
-    //            followed by an additional four or six digits and two.
-    // Czechia: Codes are seven digits in length for MO and five (not billed) or
-    //            eight (billed) for MT direction
-    //
-    // see http://en.wikipedia.org/wiki/Short_code#Regional_differences for reference
-    //
-    // However, in order to loose match 650-555-1212 and 555-1212, we need to set the min match
-    // to 7.
-    @UnsupportedAppUsage
-    static final int MIN_MATCH = 7;
-
     /**
      * Checks a given number against the list of
      * emergency numbers provided by the RIL and SIM card.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fd47561..35b435d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2418,6 +2418,10 @@
      * <p>
      * The ISO-3166 country code is provided in lowercase 2 character format.
      * <p>
+     * Note: In multi-sim, this returns a shared emergency network country iso from other
+     * subscription if the subscription used to create the TelephonyManager doesn't camp on
+     * a network due to some reason (e.g. pin/puk locked), or sim is absent in the corresponding
+     * slot.
      * Note: Result may be unreliable on CDMA networks (use {@link #getPhoneType()} to determine
      * if on a CDMA network).
      * <p>
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
new file mode 100644
index 0000000..3c343dd
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -0,0 +1,234 @@
+/*
+ * 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.ims;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.Binder;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.RcsFeature;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Manager for interfacing with the framework RCS services, including the User Capability Exchange
+ * (UCE) service, as well as managing user settings.
+ *
+ * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this manager.
+ * @hide
+ */
+public class ImsRcsManager {
+
+    /**
+     * Receives RCS availability status updates from the ImsService.
+     *
+     * @see #isAvailable(int)
+     * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
+     * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+     */
+    public static class AvailabilityCallback {
+
+        private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
+
+            private final AvailabilityCallback mLocalCallback;
+            private Executor mExecutor;
+
+            CapabilityBinder(AvailabilityCallback c) {
+                mLocalCallback = c;
+            }
+
+            @Override
+            public void onCapabilitiesStatusChanged(int config) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() ->
+                        mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(
+                                new RcsFeature.RcsImsCapabilities(config))));
+            }
+
+            @Override
+            public void onQueryCapabilityConfiguration(int capability, int radioTech,
+                    boolean isEnabled) {
+                // This is not used for public interfaces.
+            }
+
+            @Override
+            public void onChangeCapabilityConfigurationError(int capability, int radioTech,
+                    @ImsFeature.ImsCapabilityError int reason) {
+                // This is not used for public interfaces
+            }
+
+            private void setExecutor(Executor executor) {
+                mExecutor = executor;
+            }
+        }
+
+        private final CapabilityBinder mBinder = new CapabilityBinder(this);
+
+        /**
+         * The availability of the feature's capabilities has changed to either available or
+         * unavailable.
+         * <p>
+         * If unavailable, the feature does not support the capability at the current time. This may
+         * be due to network or subscription provisioning changes, such as the IMS registration
+         * being lost, network type changing, or OMA-DM provisioning updates.
+         *
+         * @param capabilities The new availability of the capabilities.
+         */
+        public void onAvailabilityChanged(RcsFeature.RcsImsCapabilities capabilities) {
+        }
+
+        /**@hide*/
+        public final IImsCapabilityCallback getBinder() {
+            return mBinder;
+        }
+
+        private void setExecutor(Executor executor) {
+            mBinder.setExecutor(executor);
+        }
+    }
+
+    private final int mSubId;
+    private final Context mContext;
+
+
+    /**
+     * Create an instance of ImsRcsManager for the subscription id specified.
+     *
+     * @param context The context to create this ImsRcsManager instance within.
+     * @param subscriptionId The ID of the subscription that this ImsRcsManager will use.
+     * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
+     * @throws IllegalArgumentException if the subscription is invalid.
+     * @hide
+     */
+    public static ImsRcsManager createForSubscriptionId(Context context, int subscriptionId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
+            throw new IllegalArgumentException("Invalid subscription ID");
+        }
+
+        return new ImsRcsManager(context, subscriptionId);
+    }
+
+    /**
+     * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this class.
+     */
+    private ImsRcsManager(Context context, int subId) {
+        mContext = context;
+        mSubId = subId;
+    }
+
+    /**
+     * Registers an {@link AvailabilityCallback} with the system, which will provide RCS
+     * availability updates for the subscription specified.
+     *
+     * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
+     * subscription changed events and call
+     * {@link #unregisterRcsAvailabilityCallback(AvailabilityCallback)} to clean up after a
+     * subscription is removed.
+     * <p>
+     * When the callback is registered, it will initiate the callback c to be called with the
+     * current capabilities.
+     *
+     * @param executor The executor the callback events should be run on.
+     * @param c The RCS {@link AvailabilityCallback} to be registered.
+     * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+     * @throws ImsException if the subscription associated with this instance of
+     * {@link ImsRcsManager} is valid, but the ImsService associated with the subscription is not
+     * available. This can happen if the ImsService has crashed, for example, or if the subscription
+     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void registerRcsAvailabilityCallback(@CallbackExecutor Executor executor,
+            @NonNull AvailabilityCallback c) throws ImsException {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        c.setExecutor(executor);
+        throw new UnsupportedOperationException("registerRcsAvailabilityCallback is not"
+                + "supported.");
+    }
+
+    /**
+     * Removes an existing RCS {@link AvailabilityCallback}.
+     * <p>
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be unregistered. If this method is called for an
+     * inactive subscription, it will result in a no-op.
+     * @param c The RCS {@link AvailabilityCallback} to be removed.
+     * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void unregisterRcsAvailabilityCallback(@NonNull AvailabilityCallback c) {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+        }
+        throw new UnsupportedOperationException("unregisterRcsAvailabilityCallback is not"
+                + "supported.");
+    }
+
+    /**
+     * Query for the capability of an IMS RCS service provided by the framework.
+     * <p>
+     * This only reports the status of RCS capabilities provided by the framework, not necessarily
+     * RCS capabilities provided over-the-top by applications.
+     *
+     * @param capability The RCS capability to query.
+     * @return true if the RCS capability is capable for this subscription, false otherwise. This
+     * does not necessarily mean that we are registered for IMS and the capability is available, but
+     * rather the subscription is capable of this service over IMS.
+     * @see #isAvailable(int)
+     * @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isCapable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+        throw new UnsupportedOperationException("isCapable is not supported.");
+    }
+
+    /**
+     * Query the availability of an IMS RCS capability.
+     * <p>
+     * This only reports the status of RCS capabilities provided by the framework, not necessarily
+     * RCS capabilities provided by over-the-top by applications.
+     *
+     * @param capability the RCS capability to query.
+     * @return true if the RCS capability is currently available for the associated subscription,
+     * false otherwise. If the capability is available, IMS is registered and the service is
+     * currently available over IMS.
+     * @see #isCapable(int)
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isAvailable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+        throw new UnsupportedOperationException("isAvailable is not supported.");
+    }
+
+    /**
+     * @return A new {@link RcsUceAdapter} used for User Capability Exchange (UCE) operations for
+     * this subscription.
+     */
+    @NonNull
+    public RcsUceAdapter getUceAdapter() {
+        return new RcsUceAdapter(mSubId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index a478606..20aba4d 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -871,6 +871,19 @@
      */
     public static final int CODE_REJECT_ONGOING_CS_CALL = 1621;
 
+    /**
+     * An attempt was made to place an emergency call over WFC when emergency services is not
+     * currently available in the current location.
+     * @hide
+     */
+    public static final int CODE_EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 1622;
+
+    /**
+     * Indicates that WiFi calling service is not available in the current location.
+     * @hide
+     */
+    public static final int CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 1623;
+
     /*
      * OEM specific error codes. To be used by OEMs when they don't want to reveal error code which
      * would be replaced by ERROR_UNSPECIFIED.
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index cc037e3..effdf48 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -387,6 +387,24 @@
         }
     }
 
+    /**
+     * Notify the framework that an RCS autoconfiguration XML file has been received for
+     * provisioning.
+     * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed.
+     * @param isCompressed The XML file is compressed in gzip format and must be decompressed
+     *         before being read.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void notifyRcsAutoConfigurationReceived(@NonNull byte[] config, boolean isCompressed) {
+        if (config == null) {
+            throw new IllegalArgumentException("Must include a non-null config XML file.");
+        }
+        // TODO: Connect to ImsConfigImplBase.
+        throw new UnsupportedOperationException("notifyRcsAutoConfigurationReceived is not"
+                + "supported");
+    }
+
     private static boolean isImsAvailableOnDevice() {
         IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
         if (pm == null) {
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.aidl b/telephony/java/android/telephony/ims/RcsContactUceCapability.aidl
new file mode 100644
index 0000000..bef6a40
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.telephony.ims;
+
+parcelable RcsContactUceCapability;
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
new file mode 100644
index 0000000..492170b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -0,0 +1,291 @@
+/*
+ * 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.ims;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Contains the User Capability Exchange capabilities corresponding to a contact's URI.
+ * @hide
+ */
+public final class RcsContactUceCapability implements Parcelable {
+
+    /** Supports 1-to-1 chat */
+    public static final int CAPABILITY_CHAT_STANDALONE = (1 << 0);
+    /** Supports group chat */
+    public static final int CAPABILITY_CHAT_SESSION = (1 << 1);
+    /** Supports full store and forward group chat information. */
+    public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = (1 << 2);
+    /**
+     * Supports file transfer via Message Session Relay Protocol (MSRP) without Store and Forward.
+     */
+    public static final int CAPABILITY_FILE_TRANSFER = (1 << 3);
+    /** Supports File Transfer Thumbnail */
+    public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = (1 << 4);
+    /** Supports File Transfer with Store and Forward */
+    public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = (1 << 5);
+    /** Supports File Transfer via HTTP */
+    public static final int CAPABILITY_FILE_TRANSFER_HTTP = (1 << 6);
+    /** Supports file transfer via SMS */
+    public static final int CAPABILITY_FILE_TRANSFER_SMS = (1 << 7);
+    /** Supports image sharing */
+    public static final int CAPABILITY_IMAGE_SHARE = (1 << 8);
+    /** Supports video sharing during a circuit-switch call (IR.74)*/
+    public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = (1 << 9);
+    /** Supports video share outside of voice call (IR.84) */
+    public static final int CAPABILITY_VIDEO_SHARE = (1 << 10);
+    /** Supports social presence information */
+    public static final int CAPABILITY_SOCIAL_PRESENCE = (1 << 11);
+    /** Supports capability discovery via presence */
+    public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = (1 << 12);
+    /** Supports IP Voice calling over LTE or IWLAN (IR.92/IR.51) */
+    public static final int CAPABILITY_IP_VOICE_CALL = (1 << 13);
+    /** Supports IP video calling (IR.94) */
+    public static final int CAPABILITY_IP_VIDEO_CALL = (1 << 14);
+    /** Supports Geolocation PUSH during 1-to-1 or multiparty chat */
+    public static final int CAPABILITY_GEOLOCATION_PUSH = (1 << 15);
+    /** Supports Geolocation PUSH via SMS for fallback.  */
+    public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = (1 << 16);
+    /** Supports Geolocation pull. */
+    public static final int CAPABILITY_GEOLOCATION_PULL = (1 << 17);
+    /** Supports Geolocation pull using file transfer support. */
+    public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = (1 << 18);
+    /** Supports RCS voice calling */
+    public static final int CAPABILITY_RCS_VOICE_CALL = (1 << 19);
+    /** Supports RCS video calling */
+    public static final int CAPABILITY_RCS_VIDEO_CALL = (1 << 20);
+    /** Supports RCS video calling, where video media can not be dropped */
+    public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = (1 << 21);
+
+    /** @hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "CAPABILITY_", flag = true, value = {
+            CAPABILITY_CHAT_STANDALONE,
+            CAPABILITY_CHAT_SESSION,
+            CAPABILITY_CHAT_SESSION_STORE_FORWARD,
+            CAPABILITY_FILE_TRANSFER,
+            CAPABILITY_FILE_TRANSFER_THUMBNAIL,
+            CAPABILITY_FILE_TRANSFER_STORE_FORWARD,
+            CAPABILITY_FILE_TRANSFER_HTTP,
+            CAPABILITY_FILE_TRANSFER_SMS,
+            CAPABILITY_IMAGE_SHARE,
+            CAPABILITY_VIDEO_SHARE_DURING_CS_CALL,
+            CAPABILITY_VIDEO_SHARE,
+            CAPABILITY_SOCIAL_PRESENCE,
+            CAPABILITY_DISCOVERY_VIA_PRESENCE,
+            CAPABILITY_IP_VOICE_CALL,
+            CAPABILITY_IP_VIDEO_CALL,
+            CAPABILITY_GEOLOCATION_PUSH,
+            CAPABILITY_GEOLOCATION_PUSH_SMS,
+            CAPABILITY_GEOLOCATION_PULL,
+            CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER,
+            CAPABILITY_RCS_VOICE_CALL,
+            CAPABILITY_RCS_VIDEO_CALL,
+            CAPABILITY_RCS_VIDEO_ONLY_CALL
+    })
+    public @interface CapabilityFlag {}
+
+    /**
+     * Builder to help construct {@link RcsContactUceCapability} instances.
+     */
+    public static class Builder {
+
+        private final RcsContactUceCapability mCapabilities;
+
+        /**
+         * Create the Builder, which can be used to set UCE capabilities as well as custom
+         * capability extensions.
+         * @param contact The contact URI that the capabilities are attached to.
+         */
+        public Builder(@NonNull Uri contact) {
+            mCapabilities = new RcsContactUceCapability(contact);
+        }
+
+        /**
+         * Add a UCE capability bit-field as well as the associated URI that the framework should
+         * use for those services. This is mainly used for capabilities that may use a URI separate
+         * from the contact's URI, for example the URI to use for VT calls.
+         * @param type The capability to map to a service URI that is different from the contact's
+         *         URI.
+         */
+        public Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) {
+            mCapabilities.mCapabilities |= type;
+            // Put each of these capabilities into the map separately.
+            for (int shift = 0; shift < Integer.SIZE; shift++) {
+                int cap = type & (1 << shift);
+                if (cap != 0) {
+                    mCapabilities.mServiceMap.put(cap, serviceUri);
+                    // remove that capability from the field.
+                    type &= ~cap;
+                }
+                if (type == 0) {
+                    // no need to keep going, end early.
+                    break;
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Add a UCE capability flag that this contact supports.
+         * @param type the capability that the contact supports.
+         */
+        public Builder add(@CapabilityFlag int type) {
+            mCapabilities.mCapabilities |= type;
+            return this;
+        }
+
+        /**
+         * Add a carrier specific service tag.
+         * @param extension A string containing a carrier specific service tag that is an extension
+         *         of the {@link CapabilityFlag}s that are defined here.
+         */
+        public Builder add(@NonNull String extension) {
+            mCapabilities.mExtensionTags.add(extension);
+            return this;
+        }
+
+        /**
+         * @return the constructed instance.
+         */
+        public RcsContactUceCapability build() {
+            return mCapabilities;
+        }
+    }
+
+    private final Uri mContactUri;
+    private int mCapabilities;
+    private List<String> mExtensionTags = new ArrayList<>();
+    private Map<Integer, Uri> mServiceMap = new HashMap<>();
+
+    /**
+     * Use {@link Builder} to build an instance of this interface.
+     * @param contact The URI associated with this capability information.
+     * @hide
+     */
+    RcsContactUceCapability(@NonNull Uri contact) {
+        mContactUri = contact;
+    }
+
+    private RcsContactUceCapability(Parcel in) {
+        mContactUri = in.readParcelable(Uri.class.getClassLoader());
+        mCapabilities = in.readInt();
+        in.readStringList(mExtensionTags);
+        // read mServiceMap as key,value pair
+        int mapSize = in.readInt();
+        for (int i = 0; i < mapSize; i++) {
+            mServiceMap.put(in.readInt(), in.readParcelable(Uri.class.getClassLoader()));
+        }
+    }
+
+    public static final Creator<RcsContactUceCapability> CREATOR =
+            new Creator<RcsContactUceCapability>() {
+        @Override
+        public RcsContactUceCapability createFromParcel(Parcel in) {
+            return new RcsContactUceCapability(in);
+        }
+
+        @Override
+        public RcsContactUceCapability[] newArray(int size) {
+            return new RcsContactUceCapability[size];
+        }
+    };
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(mContactUri, 0);
+        out.writeInt(mCapabilities);
+        out.writeStringList(mExtensionTags);
+        // write mServiceMap as key,value pairs
+        int mapSize = mServiceMap.keySet().size();
+        out.writeInt(mapSize);
+        for (int key : mServiceMap.keySet()) {
+            out.writeInt(key);
+            out.writeParcelable(mServiceMap.get(key), 0);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Query for a capability
+     * @param type The capability flag to query.
+     * @return true if the capability flag specified is set, false otherwise.
+     */
+    public boolean isCapable(@CapabilityFlag int type) {
+        return (mCapabilities & type) > 0;
+    }
+
+    /**
+     * @return true if the extension service tag is set, false otherwise.
+     */
+    public boolean isCapable(@NonNull String extensionTag) {
+        return mExtensionTags.contains(extensionTag);
+    }
+
+    /**
+     * @return An immutable list containing all of the extension tags that have been set as capable.
+     * @throws UnsupportedOperationException if this list is modified.
+     */
+    public @NonNull List<String> getCapableExtensionTags() {
+        return Collections.unmodifiableList(mExtensionTags);
+    }
+
+    /**
+     * Retrieves the {@link Uri} associated with the capability being queried.
+     * <p>
+     * This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless
+     * a different service {@link Uri} was associated with this capability using
+     * {@link Builder#add(int, Uri)}.
+     *
+     * @return a String containing the {@link Uri} associated with the service tag or
+     * {@code null} if this capability is not set as capable.
+     * @see #isCapable(int)
+     */
+    public @Nullable Uri getServiceUri(@CapabilityFlag int type) {
+        Uri result = mServiceMap.getOrDefault(type, null);
+        // If the capability is capable, but does not have a service URI associated, use the default
+        // contact URI.
+        if (result == null) {
+            return isCapable(type) ? getContactUri() : null;
+        }
+        return result;
+    }
+
+    /**
+     * @return the URI representing the contact associated with the capabilities.
+     */
+    public @NonNull Uri getContactUri() {
+        return mContactUri;
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
new file mode 100644
index 0000000..a6a7a84
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -0,0 +1,276 @@
+/*
+ * 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.ims;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.net.Uri;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Manages RCS User Capability Exchange for the subscription specified.
+ *
+ * @see ImsRcsManager#getUceAdapter() for information on creating an instance of this class.
+ * @hide
+ */
+public class RcsUceAdapter {
+
+    /**
+     * An unknown error has caused the request to fail.
+     */
+    public static final int ERROR_GENERIC_FAILURE = 1;
+    /**
+     * The carrier network does not have UCE support enabled for this subscriber.
+     */
+    public static final int ERROR_NOT_ENABLED = 2;
+    /**
+     * The data network that the device is connected to does not support UCE currently (e.g. it is
+     * 1x only currently).
+     */
+    public static final int ERROR_NOT_AVAILABLE = 3;
+    /**
+     * The network has responded with SIP 403 error and a reason "User not registered."
+     */
+    public static final int ERROR_NOT_REGISTERED = 4;
+    /**
+     * The network has responded to this request with a SIP 403 error and reason "not authorized for
+     * presence" for this subscriber.
+     */
+    public static final int ERROR_NOT_AUTHORIZED = 5;
+    /**
+     * The network has responded to this request with a SIP 403 error and no reason.
+     */
+    public static final int ERROR_FORBIDDEN = 6;
+    /**
+     * The contact URI requested is not provisioned for VoLTE or it is not known as an IMS
+     * subscriber to the carrier network.
+     */
+    public static final int ERROR_NOT_FOUND = 7;
+    /**
+     * The capabilities request contained too many URIs for the carrier network to handle. Retry
+     * with a lower number of contact numbers. The number varies per carrier.
+     */
+    // TODO: Try to integrate this into the API so that the service will split based on carrier.
+    public static final int ERROR_REQUEST_TOO_LARGE = 8;
+    /**
+     * The network did not respond to the capabilities request before the request timed out.
+     */
+    public static final int ERROR_REQUEST_TIMEOUT = 10;
+    /**
+     * The request failed due to the service having insufficient memory.
+     */
+    public static final int ERROR_INSUFFICIENT_MEMORY = 11;
+    /**
+     * The network was lost while trying to complete the request.
+     */
+    public static final int ERROR_LOST_NETWORK = 12;
+    /**
+     * The request has failed because the same request has already been added to the queue.
+     */
+    public static final int ERROR_ALREADY_IN_QUEUE = 13;
+
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "ERROR_", value = {
+            ERROR_GENERIC_FAILURE,
+            ERROR_NOT_ENABLED,
+            ERROR_NOT_AVAILABLE,
+            ERROR_NOT_REGISTERED,
+            ERROR_NOT_AUTHORIZED,
+            ERROR_FORBIDDEN,
+            ERROR_NOT_FOUND,
+            ERROR_REQUEST_TOO_LARGE,
+            ERROR_REQUEST_TIMEOUT,
+            ERROR_INSUFFICIENT_MEMORY,
+            ERROR_LOST_NETWORK,
+            ERROR_ALREADY_IN_QUEUE
+    })
+    public @interface ErrorCode {}
+
+    /**
+     * The last publish has resulted in a "200 OK" response or the device is using SIP OPTIONS for
+     * UCE.
+     */
+    public static final int PUBLISH_STATE_200_OK = 1;
+
+    /**
+     * The hasn't published its capabilities since boot or hasn't gotten any publish response yet.
+     */
+    public static final int PUBLISH_STATE_NOT_PUBLISHED = 2;
+
+    /**
+     * The device has tried to publish its capabilities, which has resulted in an error. This error
+     * is related to the fact that the device is not VoLTE provisioned.
+     */
+    public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3;
+
+    /**
+     * The device has tried to publish its capabilities, which has resulted in an error. This error
+     * is related to the fact that the device is not RCS or UCE provisioned.
+     */
+    public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4;
+
+    /**
+     * The last publish resulted in a "408 Request Timeout" response.
+     */
+    public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5;
+
+    /**
+     * The last publish resulted in another unknown error, such as SIP 503 - "Service Unavailable"
+     * or SIP 423 - "Interval too short".
+     * <p>
+     * Device shall retry with exponential back-off.
+     */
+    public static final int PUBLISH_STATE_OTHER_ERROR = 6;
+
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "PUBLISH_STATE_", value = {
+            PUBLISH_STATE_200_OK,
+            PUBLISH_STATE_NOT_PUBLISHED,
+            PUBLISH_STATE_VOLTE_PROVISION_ERROR,
+            PUBLISH_STATE_RCS_PROVISION_ERROR,
+            PUBLISH_STATE_REQUEST_TIMEOUT,
+            PUBLISH_STATE_OTHER_ERROR
+    })
+    public @interface PublishState {}
+
+
+    /**
+     * Provides a one-time callback for the response to a UCE request. After this callback is called
+     * by the framework, the reference to this callback will be discarded on the service side.
+     * @see #requestCapabilities(Executor, List, CapabilitiesCallback)
+     */
+    public static class CapabilitiesCallback {
+
+        /**
+         * Notify this application that the pending capability request has returned successfully.
+         * @param contactCapabilities List of capabilities associated with each contact requested.
+         */
+        public void onCapabilitiesReceived(
+                @NonNull List<RcsContactUceCapability> contactCapabilities) {
+
+        }
+
+        /**
+         * The pending request has resulted in an error and may need to be retried, depending on the
+         * error code.
+         * @param errorCode The reason for the framework being unable to process the request.
+         */
+        public void onError(@ErrorCode int errorCode) {
+
+        }
+    }
+
+    private final int mSubId;
+
+    /**
+     * Not to be instantiated directly, use
+     * {@link ImsRcsManager#createForSubscriptionId(Context, int)} and
+     * {@link ImsRcsManager#getUceAdapter()} to instantiate this manager class.
+     */
+    RcsUceAdapter(int subId) {
+        mSubId = subId;
+    }
+
+    /**
+     * Request the User Capability Exchange capabilities for one or more contacts.
+     * <p>
+     * Be sure to check the availability of this feature using
+     * {@link ImsRcsManager#isAvailable(int)} and ensuring
+     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
+     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else
+     * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
+     *
+     * @param executor The executor that will be used when the request is completed and the
+     *         {@link CapabilitiesCallback} is called.
+     * @param contactNumbers A list of numbers that the capabilities are being requested for.
+     * @param c A one-time callback for when the request for capabilities completes or there is an
+     *         error processing the request.
+     * @throws ImsException if the subscription associated with this instance of
+     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+     * available. This can happen if the ImsService has crashed, for example, or if the subscription
+     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void requestCapabilities(@CallbackExecutor Executor executor,
+            @NonNull List<Uri> contactNumbers,
+            @NonNull CapabilitiesCallback c) throws ImsException {
+        throw new UnsupportedOperationException("isUceSettingEnabled is not supported.");
+    }
+
+    /**
+     * Gets the last publish result from the UCE service if the device is using an RCS presence
+     * server.
+     * @return The last publish result from the UCE service. If the device is using SIP OPTIONS,
+     * this method will return {@link #PUBLISH_STATE_200_OK} as well.
+     * @throws ImsException if the subscription associated with this instance of
+     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+     * available. This can happen if the ImsService has crashed, for example, or if the subscription
+     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @PublishState int getUcePublishState() throws ImsException {
+        throw new UnsupportedOperationException("getPublishState is not supported.");
+    }
+
+    /**
+     * The user’s setting for whether or not Presence and User Capability Exchange (UCE) is enabled
+     * for the associated subscription.
+     *
+     * @return true if the user’s setting for UCE is enabled, false otherwise. If false,
+     * {@link ImsRcsManager#isCapable(int)} will return false for
+     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and
+     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE}
+     * @see #setUceSettingEnabled(boolean)
+     * @throws ImsException if the subscription associated with this instance of
+     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+     * available. This can happen if the ImsService has crashed, for example, or if the subscription
+     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isUceSettingEnabled() throws ImsException {
+        // TODO: add SubscriptionController column for this property.
+        throw new UnsupportedOperationException("isUceSettingEnabled is not supported.");
+    }
+    /**
+     * Change the user’s setting for whether or not UCE is enabled for the associated subscription.
+     * @param isEnabled the user's setting for whether or not they wish for Presence and User
+     *         Capability Exchange to be enabled. If false,
+     *         {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and
+     *         {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} capability will be
+     *         disabled, depending on which type of UCE the carrier supports.
+     * @see #isUceSettingEnabled()
+     * @throws ImsException if the subscription associated with this instance of
+     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+     * available. This can happen if the ImsService has crashed, for example, or if the subscription
+     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void setUceSettingEnabled(boolean isEnabled) throws ImsException {
+        // TODO: add SubscriptionController column for this property.
+        throw new UnsupportedOperationException("setUceSettingEnabled is not supported.");
+    }
+}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 74af6bf..3bec8b0 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -132,15 +132,20 @@
     public @interface ImsState {}
 
     /**
-     * This {@link ImsFeature}'s state is unavailable and should not be communicated with.
+     * This {@link ImsFeature}'s state is unavailable and should not be communicated with. This will
+     * remove all bindings back to the framework. Any attempt to communicate with the framework
+     * during this time will result in an {@link IllegalStateException}.
      */
     public static final int STATE_UNAVAILABLE = 0;
     /**
-     * This {@link ImsFeature} state is initializing and should not be communicated with.
+     * This {@link ImsFeature} state is initializing and should not be communicated with. This will
+     * remove all bindings back to the framework. Any attempt to communicate with the framework
+     * during this time will result in an {@link IllegalStateException}.
      */
     public static final int STATE_INITIALIZING = 1;
     /**
-     * This {@link ImsFeature} is ready for communication.
+     * This {@link ImsFeature} is ready for communication. Do not attempt to call framework methods
+     * until {@link #onFeatureReady()} is called.
      */
     public static final int STATE_READY = 2;
 
@@ -208,11 +213,14 @@
 
     /**
      * Contains the capabilities defined and supported by an ImsFeature in the form of a bit mask.
+     * <p>
+     * Typically this class is not used directly, but rather extended in subclasses of
+     * {@link ImsFeature} to provide service specific capabilities.
      * @hide
-     * @deprecated Use {@link MmTelFeature.MmTelCapabilities} instead.
      */
-    @SystemApi  // SystemApi only because it was leaked through type usage in a previous release.
+    @SystemApi
     public static class Capabilities {
+        /** @deprecated Use getters and accessors instead. */
         protected int mCapabilities = 0;
 
         /**
@@ -305,12 +313,12 @@
     /** @hide */
     protected final Object mLock = new Object();
 
-    private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap(
-            new WeakHashMap<IImsFeatureStatusCallback, Boolean>());
+    private final Set<IImsFeatureStatusCallback> mStatusCallbacks =
+            Collections.newSetFromMap(new WeakHashMap<>());
     private @ImsState int mState = STATE_UNAVAILABLE;
     private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-    private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks
-            = new RemoteCallbackList<>();
+    private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks =
+            new RemoteCallbackList<>();
     private Capabilities mCapabilityStatus = new Capabilities();
 
     /**
@@ -322,6 +330,16 @@
     }
 
     /**
+     * @return The SIM slot index associated with this ImsFeature.
+     *
+     * @see SubscriptionManager#getSubscriptionIds(int) for more information on getting the
+     * subscription IDs associated with this slot.
+     */
+    public final int getSlotIndex() {
+        return mSlotId;
+    }
+
+    /**
      * @return The current state of the feature, defined as {@link #STATE_UNAVAILABLE},
      * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}.
      * @hide
@@ -490,7 +508,9 @@
     public abstract void onFeatureRemoved();
 
     /**
-     * Called when the feature has been initialized and communication with the framework is set up.
+     * Called after this ImsFeature has been initialized and has been set to the
+     * {@link ImsState#STATE_READY} state.
+     * <p>
      * Any attempt by this feature to access the framework before this method is called will return
      * with an {@link IllegalStateException}.
      * The IMS provider should use this method to trigger registration for this feature on the IMS
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index a637e16..5fae3ee 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -16,8 +16,14 @@
 
 package android.telephony.ims.feature;
 
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.telephony.ims.aidl.IImsRcsFeature;
+import android.telephony.ims.stub.RcsPresenceExchangeImplBase;
+import android.telephony.ims.stub.RcsSipOptionsImplBase;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
@@ -32,18 +38,165 @@
         // Empty Default Implementation.
     };
 
+    /**
+     * Contains the capabilities defined and supported by a {@link RcsFeature} in the
+     * form of a bitmask. The capabilities that are used in the RcsFeature are
+     * defined as:
+     * {@link RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE}
+     * {@link RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE}
+     *
+     * The enabled capabilities of this RcsFeature will be set by the framework
+     * using {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}.
+     * After the capabilities have been set, the RcsFeature may then perform the necessary bring up
+     * of the capability and notify the capability status as true using
+     * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
+     * framework that the capability is available for usage.
+     * @hide
+     */
+    public static class RcsImsCapabilities extends Capabilities {
+        /** @hide*/
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = {
+                CAPABILITY_TYPE_OPTIONS_UCE,
+                CAPABILITY_TYPE_PRESENCE_UCE
+        })
+        public @interface RcsImsCapabilityFlag {}
 
-    public RcsFeature() {
-        super();
+        /**
+         * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the
+         * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS.
+         * If not set, this RcsFeature should not service capability requests.
+         * @hide
+         */
+        public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0;
+
+        /**
+         * This carrier supports User Capability Exchange using a presence server as defined by the
+         * framework. If set, the RcsFeature should support capability exchange using a presence
+         * server. If not set, this RcsFeature should not publish capabilities or service capability
+         * requests using presence.
+         * @hide
+         */
+        public static final int CAPABILITY_TYPE_PRESENCE_UCE =  1 << 1;
+
+        /**@hide*/
+        public RcsImsCapabilities(@RcsImsCapabilityFlag int capabilities) {
+
+        }
+
+        /**@hide*/
+        @Override
+        public void addCapabilities(@RcsImsCapabilityFlag int capabilities) {
+
+        }
+
+        /**@hide*/
+        @Override
+        public void removeCapabilities(@RcsImsCapabilityFlag int capabilities) {
+
+        }
+
+        /**@hide*/
+        @Override
+        public boolean isCapable(@RcsImsCapabilityFlag int capabilities) {
+            return false;
+        }
+    }
+    /**
+     * Query the current {@link RcsImsCapabilities} status set by the RcsFeature. If a capability is
+     * set, the {@link RcsFeature} has brought up the capability and is ready for framework
+     * requests. To change the status of the capabilities
+     * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called.
+     * @hide
+     */
+    @Override
+    public final RcsImsCapabilities queryCapabilityStatus() {
+        throw new UnsupportedOperationException();
     }
 
     /**
-     * {@inheritDoc}
+     * Notify the framework that the capabilities status has changed. If a capability is enabled,
+     * this signals to the framework that the capability has been initialized and is ready.
+     * Call {@link #queryCapabilityStatus()} to return the current capability status.
+     * @hide
+     */
+    public final void notifyCapabilitiesStatusChanged(RcsImsCapabilities c) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Provides the RcsFeature with the ability to return the framework capability configuration set
+     * by the framework. When the framework calls
+     * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} to
+     * enable or disable capability A, this method should return the correct configuration for
+     * capability A afterwards (until it has changed).
+     * @hide
+     */
+    public boolean queryCapabilityConfiguration(
+            @RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+        throw new UnsupportedOperationException();
+    }
+    /**
+     * Called from the framework when the {@link RcsImsCapabilities} that have been configured for
+     * this {@link RcsFeature} has changed.
+     * <p>
+     * For each newly enabled capability flag, the corresponding capability should be brought up in
+     * the {@link RcsFeature} and registered on the network. For each newly disabled capability
+     * flag, the corresponding capability should be brought down, and deregistered. Once a new
+     * capability has been initialized and is ready for usage, the status of that capability should
+     * also be set to true using {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This
+     * will notify the framework that the capability is ready.
+     * <p>
+     * If for some reason one or more of these capabilities can not be enabled/disabled,
+     * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError(int, int, int)} should
+     * be called for each capability change that resulted in an error.
+     * @hide
      */
     @Override
     public void changeEnabledCapabilities(CapabilityChangeRequest request,
             CapabilityCallbackProxy c) {
-        // Do nothing for base implementation.
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieve the implementation of SIP OPTIONS for this {@link RcsFeature}.
+     * <p>
+     * Will only be requested by the framework if capability exchange via SIP OPTIONS is
+     * configured as capable during a
+     * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}
+     * operation and the RcsFeature sets the status of the capability to true using
+     * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}.
+     *
+     * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if
+     * it is supported by the device.
+     * @hide
+     */
+    public RcsSipOptionsImplBase getOptionsExchangeImpl() {
+        // Base Implementation, override to implement functionality
+        return new RcsSipOptionsImplBase();
+    }
+
+    /**
+     * Retrieve the implementation of UCE presence for this {@link RcsFeature}.
+     * Will only be requested by the framework if presence exchang is configured as capable during
+     * a {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}
+     * operation and the RcsFeature sets the status of the capability to true using
+     * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}.
+     *
+     * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence
+     * exchange if it is supported by the device.
+     * @hide
+     */
+    public RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
+        // Base Implementation, override to implement functionality.
+        return new RcsPresenceExchangeImplBase();
+    }
+
+    /**
+     * Construct a new {@link RcsFeature} instance.
+     */
+    public RcsFeature() {
+        super();
     }
 
     /**{@inheritDoc}*/
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 91b0a43..3e135cc 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -348,6 +348,17 @@
     }
 
     /**
+     * The framework has received an RCS autoconfiguration XML file for provisioning.
+     *
+     * @param config The XML file to be read, if not compressed, it should be in ASCII/UTF8 format.
+     * @param isCompressed The XML file is compressed in gzip format and must be decompressed
+     *         before being read.
+     * @hide
+     */
+    public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) {
+    }
+
+    /**
      * Sets the configuration value for this ImsService.
      *
      * @param item an integer key.
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
new file mode 100644
index 0000000..289fd4c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
@@ -0,0 +1,89 @@
+/*
+ * 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.ims.stub;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Base class for different types of Capability exchange, presence using
+ * {@link RcsPresenceExchangeImplBase} and SIP OPTIONS exchange using {@link RcsSipOptionsImplBase}.
+ *
+ * @hide
+ */
+public class RcsCapabilityExchange {
+
+    /**  Service is unknown. */
+    public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0;
+    /** The command completed successfully. */
+    public static final int COMMAND_CODE_SUCCESS = 1;
+    /** The command failed with an unknown error. */
+    public static final int COMMAND_CODE_GENERIC_FAILURE = 2;
+    /**  Invalid parameter(s). */
+    public static final int COMMAND_CODE_INVALID_PARAM = 3;
+    /**  Fetch error. */
+    public static final int COMMAND_CODE_FETCH_ERROR = 4;
+    /**  Request timed out. */
+    public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5;
+    /**  Failure due to insufficient memory available. */
+    public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6;
+    /**  Network connection is lost. */
+    public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7;
+    /**  Requested feature/resource is not supported. */
+    public static final int COMMAND_CODE_NOT_SUPPORTED = 8;
+    /**  Contact or resource is not found. */
+    public static final int COMMAND_CODE_NOT_FOUND = 9;
+    /**  Service is not available. */
+    public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10;
+    /**  No Change in Capabilities */
+    public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11;
+
+    /** @hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "COMMAND_CODE_", value = {
+            COMMAND_CODE_SERVICE_UNKNOWN,
+            COMMAND_CODE_SUCCESS,
+            COMMAND_CODE_GENERIC_FAILURE,
+            COMMAND_CODE_INVALID_PARAM,
+            COMMAND_CODE_FETCH_ERROR,
+            COMMAND_CODE_REQUEST_TIMEOUT,
+            COMMAND_CODE_INSUFFICIENT_MEMORY,
+            COMMAND_CODE_LOST_NETWORK_CONNECTION,
+            COMMAND_CODE_NOT_SUPPORTED,
+            COMMAND_CODE_NOT_FOUND,
+            COMMAND_CODE_SERVICE_UNAVAILABLE,
+            COMMAND_CODE_NO_CHANGE_IN_CAP
+    })
+    public @interface CommandCode {}
+
+    /**
+     * Provides the framework with an update as to whether or not a command completed successfully
+     * locally. This includes capabilities requests and updates from the network. If it does not
+     * complete successfully, then the framework may retry the command again later, depending on the
+     * error. If the command does complete successfully, the framework will then wait for network
+     * updates.
+     *
+     * @param code The result of the pending command. If {@link #COMMAND_CODE_SUCCESS}, further
+     *             updates will be sent for this command using the associated operationToken.
+     * @param operationToken the token associated with the pending command.
+     */
+    public final void onCommandUpdate(@CommandCode int code, int operationToken) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
new file mode 100644
index 0000000..4402470
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
@@ -0,0 +1,191 @@
+/*
+ * 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.ims.stub;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.Uri;
+import android.telephony.ims.RcsContactUceCapability;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Base implementation for RCS User Capability Exchange using Presence. Any ImsService implementing
+ * this service must implement the stub methods {@link #requestCapabilities(List, int)}  and
+ * {@link #updateCapabilities(RcsContactUceCapability, int)}.
+ *
+ * @hide
+ */
+public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
+
+    private static final String LOG_TAG = "RcsPresenceExchangeIB";
+
+    /**
+     * The request has resulted in any other 4xx/5xx/6xx that is not covered below. No retry will be
+     * attempted.
+     */
+    public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1;
+
+    /**
+     * The request has succeeded with a “200” message from the network.
+     */
+    public static final int RESPONSE_SUCCESS = 0;
+
+    /**
+     * The request has resulted in a “403” (User Not Registered) error from the network. Will retry
+     * capability polling with an exponential backoff.
+     */
+    public static final int RESPONSE_NOT_REGISTERED = 1;
+
+    /**
+     * The request has resulted in a “403” (not authorized (Requestor)) error from the network. No
+     * retry will be attempted.
+     */
+    public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2;
+
+    /**
+     * The request has resulted in a "403” (Forbidden) or other “403” error from the network and
+     * will be handled the same as “404” Not found. No retry will be attempted.
+     */
+    public static final int RESPONSE_FORBIDDEN = 3;
+
+    /**
+     * The request has resulted in a “404” (Not found) result from the network. No retry will be
+     * attempted.
+     */
+    public static final int RESPONSE_NOT_FOUND = 4;
+
+    /**
+     * The request has resulted in a “408” response. Retry after exponential backoff.
+     */
+    public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5;
+
+    /**
+     *  The network has responded with a “413” (Too Large) response from the network. Capability
+     *  request contains too many items and must be shrunk before the request will be accepted.
+     */
+    public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6;
+
+    /**
+     * The request has resulted in a “423” response. Retry after exponential backoff.
+     */
+    public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7;
+
+    /**
+     * The request has resulted in a “503” response. Retry after exponential backoff.
+     */
+    public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8;
+
+    /** @hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "RESPONSE_", value = {
+            RESPONSE_SUBSCRIBE_GENERIC_FAILURE,
+            RESPONSE_SUCCESS,
+            RESPONSE_NOT_REGISTERED,
+            RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE,
+            RESPONSE_FORBIDDEN,
+            RESPONSE_NOT_FOUND,
+            RESPONSE_SIP_REQUEST_TIMEOUT,
+            RESPONSE_SUBSCRIBE_TOO_LARGE,
+            RESPONSE_SIP_INTERVAL_TOO_SHORT,
+            RESPONSE_SIP_SERVICE_UNAVAILABLE
+    })
+    public @interface PresenceResponseCode {}
+
+    /**
+     * Provide the framework with a subsequent network response update to
+     * {@link #updateCapabilities(RcsContactUceCapability, int)} and
+     * {@link #requestCapabilities(List, int)} operations.
+     * @param code The SIP response code sent from the network for the operation token specified.
+     * @param reason The optional reason response from the network. If the network provided no
+     *         reason with the code, the string should be empty.
+     * @param operationToken The token associated with the operation this service is providing a
+     *         response for.
+     */
+    public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason,
+            int operationToken) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Provides the framework with the requested contacts’ capabilities requested by the framework
+     * using {@link #requestCapabilities(List, int)} .
+     */
+    public final void onCapabilityRequestResponse(@NonNull List<RcsContactUceCapability> infos,
+            int operationToken) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Trigger the framework to provide a capability update using
+     * {@link #updateCapabilities(RcsContactUceCapability, int)}. This is typically used when trying
+     * to generate an initial PUBLISH for a new subscription to the network.
+     * <p>
+     * The device will cache all presence publications after boot until this method is called once.
+     */
+    public final void onNotifyUpdateCapabilites() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Notify the framework that the device’s capabilities have been unpublished from the network.
+     */
+    public final void onUnpublish() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * The user capabilities of one or multiple contacts have been requested.
+     * <p>
+     * This must be followed up with one call to {@link #onCommandUpdate(int, int)} with an update
+     * as to whether or not the command completed as well as subsequent network
+     * updates using {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
+     * {@link #onCapabilityRequestResponse(List, int)}  should be called with
+     * the presence information for the contacts specified.
+     * @param uris A {@link List} of the URIs that the framework is requesting the UCE capabilities
+     *          for.
+     * @param operationToken The token associated with this operation. Updates to this request using
+     *         {@link #onCommandUpdate(int, int)}, {@link #onNetworkResponse(int, String, int)}, and
+     *         {@link #onCapabilityRequestResponse(List, int)}  must use the same operation token
+     *         in response.
+     */
+    public void requestCapabilities(@NonNull List<Uri> uris, int operationToken) {
+        // Stub - to be implemented by service
+        Log.w(LOG_TAG, "requestCapabilities called with no implementation.");
+        onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+    }
+
+    /**
+     * The capabilities of this device have been updated and should be published
+     * to the network. The framework will expect one {@link #onCommandUpdate(int, int)} call to
+     * indicate whether or not this operation failed first as well as network response
+     * updates to this update using {@link #onNetworkResponse(int, String, int)}.
+     * @param capabilities The capabilities for this device.
+     * @param operationToken The token associated with this operation. Any subsequent
+     *         {@link #onCommandUpdate(int, int)} or {@link #onNetworkResponse(int, String, int)}
+     *         calls regarding this update must use the same token.
+     */
+    public void updateCapabilities(@NonNull RcsContactUceCapability capabilities,
+            int operationToken) {
+        // Stub - to be implemented by service
+        Log.w(LOG_TAG, "updateCapabilities called with no implementation.");
+        onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
new file mode 100644
index 0000000..3343074
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
@@ -0,0 +1,169 @@
+/*
+ * 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.ims.stub;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.telephony.ims.RcsContactUceCapability;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Base implementation for RCS User Capability Exchange using SIP OPTIONS.
+ *
+ * @hide
+ */
+public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
+
+    private static final String LOG_TAG = "RcsSipOptionsImplBase";
+
+    /**
+     * Indicates a SIP response from the remote user other than 200, 480, 408, 404, or 604.
+     */
+    public static final int RESPONSE_GENERIC_FAILURE = -1;
+
+    /**
+     * Indicates that the remote user responded with a 200 OK response.
+     */
+    public static final int RESPONSE_SUCCESS = 0;
+
+    /**
+     * Indicates that the remote user responded with a 480 TEMPORARY UNAVAILABLE response.
+     */
+    public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1;
+
+    /**
+     * Indicates that the remote user responded with a 408 REQUEST TIMEOUT response.
+     */
+    public static final int RESPONSE_REQUEST_TIMEOUT = 2;
+
+    /**
+     * Indicates that the remote user responded with a 404 NOT FOUND response.
+     */
+    public static final int RESPONSE_NOT_FOUND = 3;
+
+    /**
+     * Indicates that the remote user responded with a 604 DOES NOT EXIST ANYWHERE response.
+     */
+    public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4;
+
+    /** @hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "RESPONSE_", value = {
+            RESPONSE_GENERIC_FAILURE,
+            RESPONSE_SUCCESS,
+            RESPONSE_TEMPORARILY_UNAVAILABLE,
+            RESPONSE_REQUEST_TIMEOUT,
+            RESPONSE_NOT_FOUND,
+            RESPONSE_DOES_NOT_EXIST_ANYWHERE
+    })
+    public @interface SipResponseCode {}
+
+    /**
+     * Send the response of a SIP OPTIONS capability exchange to the framework. If {@code code} is
+     * {@link #RESPONSE_SUCCESS}, info must be non-null.
+     * @param code The SIP response code that was sent by the network in response to the request
+     *        sent by {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+     * @param reason The optional SIP response reason sent by the network. If none was sent, this
+     *        should be an empty string.
+     * @param info the contact's UCE capabilities associated with the capability request.
+     * @param operationToken The token associated with the original capability request, set by
+     *        {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+     */
+    public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason,
+            @Nullable RcsContactUceCapability info, int operationToken) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Inform the framework of a query for this device's UCE capabilities.
+     * <p>
+     * The framework will respond via the
+     * {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)} or
+     * {@link #respondToCapabilityRequestWithError(Uri, int, String, int)} method.
+     * @param contactUri The URI associated with the remote contact that is requesting capabilities.
+     * @param remoteInfo The remote contact's capability information.
+     * @param operationToken An unique operation token that you have generated that will be returned
+     *         by the framework in
+     *         {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}.
+     */
+    public final void onRemoteCapabilityRequest(@NonNull Uri contactUri,
+            @NonNull RcsContactUceCapability remoteInfo, int operationToken) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
+     * in order to receive the capabilities of the remote user in response.
+     * <p>
+     * The implementer must call
+     * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} to send the
+     * response of this query back to the framework.
+     * @param contactUri The URI of the remote user that we wish to get the capabilities of.
+     * @param capabilities The capabilities of this device to send to the remote user.
+     * @param operationToken A token generated by the framework that will be passed through
+     * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} when this
+     *         operation has succeeded.
+     */
+    public void sendCapabilityRequest(@NonNull Uri contactUri,
+            @NonNull RcsContactUceCapability capabilities, int operationToken) {
+        // Stub - to be implemented by service
+        Log.w(LOG_TAG, "sendCapabilityRequest called with no implementation.");
+        onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+    }
+
+    /**
+     * Respond to a remote capability request from the contact specified with the capabilities of
+     * this device.
+     * <p>
+     * The framework will use the same token and uri as what was passed in to
+     * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+     * @param contactUri The URI of the remote contact.
+     * @param ownCapabilities The capabilities of this device.
+     * @param operationToken The token generated by the framework that this service obtained when
+     *         {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
+     */
+    public void respondToCapabilityRequest(@NonNull String contactUri,
+            @NonNull RcsContactUceCapability ownCapabilities, int operationToken) {
+        // Stub - to be implemented by service
+        Log.w(LOG_TAG, "respondToCapabilityRequest called with no implementation.");
+        onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+    }
+
+    /**
+     * Respond to a remote capability request from the contact specified with the specified error.
+     * <p>
+     * The framework will use the same token and uri as what was passed in to
+     * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+     * @param contactUri A URI containing the remote contact.
+     * @param code The SIP response code to respond with.
+     * @param reason A non-null String containing the reason associated with the SIP code.
+     * @param operationToken The token provided by the framework when
+     *         {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
+     *
+     */
+    public void respondToCapabilityRequestWithError(@NonNull Uri contactUri,
+            @SipResponseCode int code, @NonNull String reason, int operationToken) {
+        // Stub - to be implemented by service
+        Log.w(LOG_TAG, "respondToCapabiltyRequestWithError called with no implementation.");
+        onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index dcfd193..a65acac 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -319,6 +319,7 @@
     /**
      * Replaced by getDataActivityForSubId.
      */
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     int getDataActivity();
 
     /**
@@ -336,6 +337,7 @@
     /**
      * Replaced by getDataStateForSubId.
      */
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     int getDataState();
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index dc026d4..98fee83 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -49,8 +49,10 @@
     void notifySignalStrengthForPhoneId(in int phoneId, in int subId,
             in SignalStrength signalStrength);
     void notifyMessageWaitingChangedForPhoneId(in int phoneId, in int subId, in boolean mwi);
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void notifyCallForwardingChanged(boolean cfi);
     void notifyCallForwardingChangedForSubscriber(in int subId, boolean cfi);
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void notifyDataActivity(int state);
     void notifyDataActivityForSubscriber(in int subId, int state);
     void notifyDataConnection(int state, boolean isDataConnectivityPossible,
@@ -63,8 +65,10 @@
     @UnsupportedAppUsage
     void notifyDataConnectionFailed(String apnType);
     void notifyDataConnectionFailedForSubscriber(int phoneId, int subId, String apnType);
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void notifyCellLocation(in Bundle cellLocation);
     void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation);
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     void notifyOtaspChanged(in int subId, in int otaspMode);
     @UnsupportedAppUsage
     void notifyCellInfo(in List<CellInfo> cellInfo);
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 98f52cb..6df5457 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -158,7 +158,7 @@
                 ApplicationInfo appInfo;
                 try {
                     appInfo = pm.getApplicationInfoAsUser(mPackageName, 0,
-                            UserHandle.getUserId(mUid));
+                            UserHandle.getUserHandleForUid(mUid));
                 } catch (NameNotFoundException e) {
                     return null;
                 }
@@ -300,7 +300,7 @@
                 Uri.fromParts(SCHEME_SMSTO, "", null));
         List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent,
                 PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                userId);
+                UserHandle.getUserHandleForUid(userId));
         for (ResolveInfo resolveInfo : respondServices) {
             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
             if (serviceInfo == null) {
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 51c5d12..67103bf 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -178,7 +178,7 @@
         // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
         // revoked.
         AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage)
+        return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage)
                 == AppOpsManager.MODE_ALLOWED;
     }
 
@@ -226,7 +226,7 @@
         // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
         // revoked.
         AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage) ==
+        return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage) ==
                 AppOpsManager.MODE_ALLOWED;
     }
 
@@ -367,7 +367,7 @@
         ApplicationInfo callingPackageInfo = null;
         try {
             callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
-                    callingPackage, 0, UserHandle.getUserId(uid));
+                    callingPackage, 0, UserHandle.getUserHandleForUid(uid));
             if (callingPackageInfo != null) {
                 if (callingPackageInfo.isSystemApp()) {
                     isPreinstalled = true;
@@ -448,7 +448,7 @@
         // We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been
         // revoked.
         AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        return appOps.noteOp(AppOpsManager.OP_READ_CALL_LOG, uid, callingPackage) ==
+        return appOps.noteOp(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage) ==
                 AppOpsManager.MODE_ALLOWED;
     }
 
@@ -471,7 +471,7 @@
             String callingPackage, String message) {
         // Default SMS app can always read it.
         AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        if (appOps.noteOp(AppOpsManager.OP_WRITE_SMS, uid, callingPackage) ==
+        if (appOps.noteOp(AppOpsManager.OPSTR_WRITE_SMS, uid, callingPackage) ==
                 AppOpsManager.MODE_ALLOWED) {
             return true;
         }
@@ -488,25 +488,18 @@
         // Can be read with READ_SMS too.
         try {
             context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message);
-            int opCode = AppOpsManager.permissionToOpCode(android.Manifest.permission.READ_SMS);
-            if (opCode != AppOpsManager.OP_NONE) {
-                return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED;
-            } else {
-                return true;
-            }
+            return appOps.noteOp(AppOpsManager.OPSTR_READ_SMS, uid, callingPackage)
+                == AppOpsManager.MODE_ALLOWED;
+
         } catch (SecurityException readSmsSecurityException) {
         }
         // Can be read with READ_PHONE_NUMBERS too.
         try {
             context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid,
                     message);
-            int opCode = AppOpsManager.permissionToOpCode(
-                    android.Manifest.permission.READ_PHONE_NUMBERS);
-            if (opCode != AppOpsManager.OP_NONE) {
-                return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED;
-            } else {
-                return true;
-            }
+            return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, uid, callingPackage)
+                == AppOpsManager.MODE_ALLOWED;
+
         } catch (SecurityException readPhoneNumberSecurityException) {
         }
 
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh
index fe3adf9..bc1aae0 100755
--- a/tests/Codegen/runTest.sh
+++ b/tests/Codegen/runTest.sh
@@ -10,7 +10,7 @@
         return $?
     }
 
-    header_and_eval m -j16 codegen && \
+    header_and_eval m -j16 codegen_cli && \
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \
         cd $ANDROID_BUILD_TOP &&
         header_and_eval mmma -j16 frameworks/base/tests/Codegen && \
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 03127ec..f69a092 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -339,8 +339,8 @@
 
 
 
-    // Code below generated by codegen v0.0.1.
-    //   on Jul 17, 2019, 5:10:26 PM PDT
+    // Code below generated by codegen v1.0.0.
+    //   on Jul 29, 2019, 2:50:21 PM PDT
     //
     // DO NOT MODIFY!
     //
@@ -409,8 +409,8 @@
     public @interface StateName {}
 
     @DataClass.Generated(
-            time = 1563408627046L,
-            codegenVersion = "0.0.1",
+            time = 1564437021513L,
+            codegenVersion = "1.0.0",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
             inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate  java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate  android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.DateParcelling.class) java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) java.util.regex.Pattern mPattern\nprivate  java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate  boolean mActive\nprivate @com.android.codegentest.SampleDataClass.StateName java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic  java.lang.CharSequence charSeq\nprivate final  android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=4L) int mLimited\nprivate @android.annotation.Size(2L) @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)")
 
diff --git a/tests/JobSchedulerPerfTests/Android.bp b/tests/JobSchedulerPerfTests/Android.bp
index 2230807..c51b811 100644
--- a/tests/JobSchedulerPerfTests/Android.bp
+++ b/tests/JobSchedulerPerfTests/Android.bp
@@ -19,6 +19,7 @@
         "androidx.test.rules",
         "apct-perftests-utils",
         "services",
+        "jobscheduler-service",
     ],
     platform_apis: true,
     certificate: "platform",
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 54f0816..31aa249 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -468,14 +468,12 @@
     }
     if (platformVersionName) {
       printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
-    }
-    if (platformVersionNameInt) {
+    } else if (platformVersionNameInt) {
       printer->Print(StringPrintf(" platformBuildVersionName='%d'", *platformVersionNameInt));
     }
     if (platformVersionCode) {
       printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
-    }
-    if (platformVersionCodeInt) {
+    } else if (platformVersionCodeInt) {
       printer->Print(StringPrintf(" platformBuildVersionCode='%d'", *platformVersionCodeInt));
     }
     if (compilesdkVersion) {
diff --git a/tools/codegen/Android.bp b/tools/codegen/Android.bp
index 805b296..677bee2 100644
--- a/tools/codegen/Android.bp
+++ b/tools/codegen/Android.bp
@@ -1,5 +1,5 @@
 java_binary_host {
-    name: "codegen",
+    name: "codegen_cli",
     manifest: "manifest.txt",
     srcs: [
         "src/**/*.kt",
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 41641f6..175eea6 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,4 +1,4 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "0.0.1"
\ No newline at end of file
+const val CODEGEN_VERSION = "1.0.0"
\ No newline at end of file
diff --git a/tools/dump-coverage/README.md b/tools/dump-coverage/README.md
index 2bab4bc..d1c10bc 100644
--- a/tools/dump-coverage/README.md
+++ b/tools/dump-coverage/README.md
@@ -16,7 +16,7 @@
 Then we can run the command to dump the data:
 
 ```
-adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=dump:/data/data/com.android.deskclock/folder-to-use'
+adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=dump:/data/data/com.android.deskclock/folder-to-use/coverage-file.ec'
 ```
 
 We can also reset the coverage information with
@@ -28,10 +28,10 @@
 then perform more actions, then dump the data again. To get the files, we can get
 
 ```
-adb pull /data/data/com.android.deskclock/folder-to-use ~/path-on-your-computer
+adb pull /data/data/com.android.deskclock/folder-to-use/coverage-file.ec ~/path-on-your-computer
 ```
 
-And you should have timestamped `.exec` files on your machine under the folder `~/path-on-your-computer`
+And you should have `coverage-file.ec` on your machine under the folder `~/path-on-your-computer`
 
 # Details
 
diff --git a/tools/dump-coverage/dump_coverage.cc b/tools/dump-coverage/dump_coverage.cc
index 3de1865..0808e77 100644
--- a/tools/dump-coverage/dump_coverage.cc
+++ b/tools/dump-coverage/dump_coverage.cc
@@ -18,20 +18,10 @@
 #include <jvmti.h>
 #include <string.h>
 
-#include <atomic>
-#include <ctime>
 #include <fstream>
-#include <iomanip>
-#include <iostream>
-#include <istream>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <vector>
 
 using std::get;
 using std::tuple;
-using std::chrono::system_clock;
 
 namespace dump_coverage {
 
@@ -87,35 +77,11 @@
   return java_result_array;
 }
 
-// Gets the filename to write execution data to
-//  dirname: the directory in which to place the file
-//  outputs <dirname>/YYYY-MM-DD-HH-MM-SS.SSS.exec
-static std::string GetFilename(const std::string& dirname) {
-  system_clock::time_point time_point = system_clock::now();
-  auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(time_point);
-  auto fractional_time = time_point - seconds;
-  auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(fractional_time);
-
-  std::time_t time = system_clock::to_time_t(time_point);
-  auto tm = *std::gmtime(&time);
-
-  std::ostringstream oss;
-  oss
-    << dirname
-    << "/"
-    << std::put_time(&tm, "%Y-%m-%d-%H-%M-%S.")
-    << std::setfill('0') << std::setw(3) << millis.count()
-    << ".ec";
-  return oss.str();
-}
-
-// Writes the execution data to a file
-//  data, length: represent the data, as a sequence of bytes
-//  dirname: directory name to contain the file
+// Writes the execution data to a file.
+//  data, length: represent the data, as a sequence of bytes.
+//  filename: file to write coverage data to.
 //  returns JNI_ERR if there is an error in writing the file, otherwise JNI_OK.
-static jint WriteFile(const char* data, int length, const std::string& dirname) {
-  auto filename = GetFilename(dirname);
-
+static jint WriteFile(const char* data, int length, const std::string& filename) {
   LOG(INFO) << "Writing file of length " << length << " to '" << filename
             << "'";
   std::ofstream file(filename, std::ios::binary);
@@ -136,11 +102,11 @@
   return JNI_OK;
 }
 
-// Grabs execution data and writes it to a file
-//  dirname: directory name to contain the file
+// Grabs execution data and writes it to a file.
+//  filename: file to write coverage data to.
 //  returns JNI_ERR if there is an error writing the file.
 // Will crash if the Agent isn't found or if any Java Exception occurs.
-static jint Dump(const std::string& dirname) {
+static jint Dump(const std::string& filename) {
   LOG(INFO) << "Dumping file";
 
   JNIEnv* env = GetJNIEnv();
@@ -152,12 +118,12 @@
 
   int result_len = env->GetArrayLength(java_result_array);
 
-  return WriteFile((const char*) result_ptr, result_len, dirname);
+  return WriteFile((const char*) result_ptr, result_len, filename);
 }
 
 // Resets execution data, performing the equivalent of
 //  Agent.getInstance().reset();
-//  args: should be empty
+//  args: should be empty.
 //  returns JNI_ERR if the arguments are invalid.
 // Will crash if the Agent isn't found or if any Java Exception occurs.
 static jint Reset(const std::string& args) {
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index 9e51180..e5ec17a 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -125,6 +125,7 @@
 
         val lastGenerated = annotationParams["time"] as Long
         val codegenVersion = annotationParams["codegenVersion"] as String
+        val codegenMajorVersion = codegenVersion.substringBefore(".")
         val sourceRelative = File(annotationParams["sourceFile"] as String)
 
         val lastGenInputSignatures = (annotationParams["inputSignatures"] as String).lines().toSet()
@@ -151,7 +152,7 @@
             stale += Stale(clazz, source, lastGenerated)
         }
 
-        if (codegenVersion != CODEGEN_VERSION) {
+        if (codegenMajorVersion != CODEGEN_VERSION.substringBefore(".")) {
             stale += Stale(clazz, source, lastGenerated)
         }
     }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1829baa..931e5dd 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -205,6 +205,8 @@
 
     int removeNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName);
 
+    List<WifiNetworkSuggestion> getNetworkSuggestions(in String packageName);
+
     String[] getFactoryMacAddresses();
 
     void setDeviceMobilityState(int state);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 89ed080..20d772c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -671,6 +671,14 @@
     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
 
     /**
+     * Broadcast intent action indicating that the wifi network settings
+     * had been reset.
+     * @hide
+     */
+    public static final String WIFI_NETWORK_SETTINGS_RESET_ACTION =
+            "android.net.wifi.action.NETWORK_SETTINGS_RESET";
+
+    /**
      * Broadcast intent action indicating that a connection to the supplicant has
      * been established (and it is now possible
      * to perform Wi-Fi operations) or the connection to the supplicant has been
@@ -1714,6 +1722,21 @@
     }
 
     /**
+     * Get all network suggestions provided by the calling app.
+     * See {@link #addNetworkSuggestions(List)}
+     * See {@link #removeNetworkSuggestions(List)}
+     * @return a list of {@link WifiNetworkSuggestion}
+     */
+    @RequiresPermission(ACCESS_WIFI_STATE)
+    public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() {
+        try {
+            return mService.getNetworkSuggestions(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
      * Returns the max number of network suggestions that are allowed per app on the device.
      * @see #addNetworkSuggestions(List)
      * @see #removeNetworkSuggestions(List)
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index fcf8bd5..bc06e7d 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -440,6 +440,11 @@
     }
 
     @Override
+    public List<WifiNetworkSuggestion> getNetworkSuggestions(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public String[] getFactoryMacAddresses() {
         throw new UnsupportedOperationException();
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index b75a1ac..e478f38 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1313,20 +1313,27 @@
     }
 
     /**
-     * Verify calls to {@link WifiManager#addNetworkSuggestions(List)} and
+     * Verify calls to {@link WifiManager#addNetworkSuggestions(List)},
+     * {@link WifiManager#getNetworkSuggestions()} and
      * {@link WifiManager#removeNetworkSuggestions(List)}.
      */
     @Test
-    public void addRemoveNetworkSuggestions() throws Exception {
+    public void addGetRemoveNetworkSuggestions() throws Exception {
+        List<WifiNetworkSuggestion> testList = new ArrayList<>();
         when(mWifiService.addNetworkSuggestions(any(List.class), anyString()))
                 .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
         when(mWifiService.removeNetworkSuggestions(any(List.class), anyString()))
                 .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
+        when(mWifiService.getNetworkSuggestions(anyString()))
+                .thenReturn(testList);
 
         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
-                mWifiManager.addNetworkSuggestions(new ArrayList<>()));
+                mWifiManager.addNetworkSuggestions(testList));
         verify(mWifiService).addNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME));
 
+        assertEquals(testList, mWifiManager.getNetworkSuggestions());
+        verify(mWifiService).getNetworkSuggestions(eq(TEST_PACKAGE_NAME));
+
         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
                 mWifiManager.removeNetworkSuggestions(new ArrayList<>()));
         verify(mWifiService).removeNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME));